Connecting to MT5 using Python
TL;DR
Previous posts on Analysing Derivatives Data with MetaTrader and Python
(part 1, part 2 and part 3) dealt with the correlation between order flow and price trends using cumulative delta metric. The manual step for downloading candle and tick data from MetraTrader 5 is a challenge in creating an automated, closed loop system to analyze tick data and take actions. In this post the use of MetaTrader Python module will be presented as an option to close this gap.
Getting data
To recreate the analysis made previously in an automated way, it is necessary to collected tick data from MT5 related to a specific time window. First, the MetaTrader Python module should be installed:
pip install MetaTrader5
It is relevant to remember that the module was designed to work in a Windows machine, so the installation will not work on Linux, for example.
After installing, the following should run successfully:
import MetaTrader5 as mt5
import dateparser
def get_tick_data(
ticker,
start_date,
end_date,
):= pd.DataFrame()
tick_data
if mt5.initialize():
= dateparser.parse(end_date)
date_to = dateparser.parse(start_date)
date_from
= mt5.copy_ticks_range(ticker,
ticks
date_from,
date_to,
mt5.COPY_TICKS_TRADE)
= pd.DataFrame(ticks)
tick_data
"datetime"] = pd.to_datetime(tick_data["time_msc"], unit="ms")
tick_data[
else:
print(f"MT5 error: \n{mt5.last_error()}")
return tick_data
print(
get_tick_data("MESM23",
"2023-05-05 14:00:00 UTC+0000",
"2023-05-05 14:10:00 UTC+0000"
) )
The get_tick_data
function will first initialize MetaTrader 5: if the application is not running, it will be opened and the default user account will be activated. If any error occurs on this step, a message will be given.
In the next step the start and end dates will be parsed from the string representation to datetime.datetime
objects. The UTC+0000
at the end of the strings ensures that the dates are created with the UTC timezone, used by MT5 as default.
With the parsed dates, the function copy_ticks_range
is called in order to retrieve all the tick data relative to the trades that took place in the time window between start_date
and end_date
. The raw data is transformed into a pandas.DataFrame
and the time_msc
column in raw data, which contains epoch timestamps of the trades, is used as the basis for a new column, datetime
, with a Python datetime
object representing the timestamp.
A sample output of copy_ticks_range
is show in Figure 1 below.
One difference between those data records and the tick data collected using MT5 export interface is the value range of flags
. The sell
trades were identified with flag 88
, while now the value 344
is used. This changes the logic of calculating the delta and should be taken into consideration.
Creating charts
The return value of get_tick_data
function has all the columns needed by the code used in the previous post and can be used to create similar chart and support the analysis process. The 10 minutes of data between 14:00 and 14:10 of May 5th 2023 are represented as OHLC and delta metric in Figure 2 below.
Continuous monitoring
Besides the collection and processing of tick data for offline analysis, on which historical data is used to generate charts and correlate order flow and price, it is interesting to use the MT5 Python module as a continuous monitoring tool, allowing for automated trading if specific conditions are true.
After the initial analysis made, a first simple strategy could be to issue a buy market order if the current 10-second rolling sum of the delta is above 500
; and issue a sell market order if it is below -500
.
In order to do that, it is first necessary to monitor the metric continuously, given the current time as input to the time window. A slight modification on the get_tick_data
, as shown below, will return the most recent 3-minute tick data window.
import MetaTrader5 as mt5
import dateparser
def get_tick_data(
ticker,
start_date,
end_date,
):= pd.DataFrame()
tick_data
if mt5.initialize():
if start_date is None or end_date is None:
= datetime.datetime.now(datetime.timezone.utc)
date_to = date_to - datetime.timedelta(minutes=3)
date_from else:
= dateparser.parse(end_date)
date_to = dateparser.parse(start_date)
date_from
= mt5.copy_ticks_range(ticker,
ticks
date_from,
date_to,
mt5.COPY_TICKS_TRADE)
= pd.DataFrame(ticks)
tick_data
"datetime"] = pd.to_datetime(tick_data["time_msc"], unit="ms")
tick_data[
else:
print(f"MT5 error: \n{mt5.last_error()}")
return tick_data
print(
get_tick_data("MESM23",
None,
None
) )
By monitoring the most recent record in the data frame containing the delta values, it is possible to monitor the condition that will trigger a trading action. When that occurs, the following functions can be called:
def market_order(ticker, order_type, volume=1.0):
= mt5.positions_get(symbol=ticker)
open_positions if len(open_positions) == 0:
= {
request "action": mt5.TRADE_ACTION_DEAL,
"symbol": ticker,
"volume": volume,
"type": order_type,
}
= mt5.order_send(request)
result print(result)
The function verifies if there is already an open position before taking any action. This avoids sending multiple orders related to the same triggering condition. The request
dictionary contains the bare minimum options to the order, the most relevant of which is the type
, which in our example will be equal to either mt5.ORDER_TYPE_BUY
or mt5.ORDER_TYPE_SELL
for going long or short, respectively, on the ticker.
It is also necessary to enable algorithmic trading on MT5 interface, as shown in Figure 3 below.
The complete code used in this post can be found in this GitHub gist.
Conclusion
MetaTrader Python module can be regarded as a useful tool to automate the collection of tick data for offline analysis and also as the basis for an algorithmic trading system. A simple trading strategy was shown for informational purposes but an important step towards using it in a real context would be to evaluate how effectively it would have performed in previous market conditions. This process, called backtesting
, will be the topic of an upcoming post.
Disclaimer
Futures and options trading has large potential rewards, but also large potential risk. You must be aware of the risks and be willing to accept them in order to invest in the futures and options markets. Do not trade with money you can not afford to lose. This post is neither a solicitation nor an offer to buy or sell futures or options. No representation is being made that any account will or is likely to achieve profits or losses similar to those discussed. The past performance of any trading system or methodology is not necessarily indicative of future results.
This post is provided for informational and educational purposes only. This material neither is, nor should be construed as an offer, solicitation, or recommendation to buy or sell any securities. Any investment decisions made by the reader through the use of this content is solely based on the reader independent analysis, taking into consideration their financial circumstances and risk tolerance. The author shall not be liable for any errors or for any actions taken in reliance thereon.
The references made to MT5 and AMP Global in this post do not represent a recommendation. I am not affiliated to neither platform, service nor their parent companies.