Abstract
This document explains how I built an automated trading bot for the Forex market using my knowledge in MQL5, C, and C++ programming, my experience as a day trader, and my experience as a banking advisor at the Royal Bank of Canada (RBC).
The bot trades based on price action and market structure, focusing on support and resistance levels without using traditional indicators. I also integrated machine learning to help the bot adapt to market conditions by predicting key factors like lookback periods for different timeframes.
Key features include dynamic risk management with trailing stops, position sizing based on account balance, support levels, resistance levels, and Fibonacci retracements for trade entries and exits. The bot has shown consistent profitability in backtesting, with plans to enhance adaptability using reinforcement learning.
This project showcases skills relevant to Data Scientist and Data Analyst roles, such as data handling, analysis, and applying machine learning techniques.
Technologies and Tools
• Languages: MQL5, Python (Pandas, NumPy, Scikit-learn, TensorFlow)
• Development Environments: MetaTrader 5, Jupyter Notebook
• Machine Learning: Bayesian Optimization, Reinforcement Learning (future feature)
• Data Visualization: Matplotlib
• Version Control: Git
Introduction
Background
I have been a day trader for about four years and worked at the Royal Bank of Canada, where I learned much about financial markets. My goal with this project was to create a trading bot that reflects my trading approach, which is focused on price action and market structure without relying on traditional indicators.
Trading in fast-moving markets requires quick decisions and precise strategies. I wanted to automate my trading process to make it more consistent and reduce emotional decision-making. By adding machine learning, I also aimed to improve the bot’s ability to adjust to different market conditions, making it smarter and more reliable.
This project also allowed me to demonstrate my skills in areas important to quantitative trading.
Objectives
• Build a trading bot using MQL5 that trades based on price levels and Fibonacci retracements.
• Use machine learning to optimize parameters like lookback periods.
• Add risk management with trailing stops and dynamic position sizing.
• Demonstrate skills important to Data Scientist, Quantitative Trading, and Data Analyst roles through data handling and analysis.
• Use machine learning to optimize parameters like lookback periods.
• Add risk management with trailing stops and dynamic position sizing.
• Demonstrate skills important to Data Scientist, Quantitative Trading, and Data Analyst roles through data handling and analysis.
Learning MQL5
Transition from C/C++ to MQL5
Since MQL5 is similar to C and C++, learning it was straightforward for me. MQL5 is designed for developing trading strategies on the MetaTrader 5 platform, and while it shares a lot with C++, there were new concepts I had to get used to, like event-driven programming for handling trade execution.
Learning Curve
At first, I had to get used to the specific functions and event-driven structure of MQL5, like `OnInit()`, `OnDeinit()`, and `OnTick()`. Learning how to manage real-time market data and trades in MQL5’s `OnTick()` function required some adjustment but resources like the MQL5 documentation and online forums were very helpful.
Applying Existing Knowledge
My background in programming helped me understand complex concepts in MQL5 quickly, such as data structures and algorithm optimization. As I was working on a project that required fast calculations, I needed the best time complexity.
Trading Strategy Design
Trading Philosophy
Price Action and Market Structure
The bot relies on analyzing raw price data (Open, High, Low, Close) and calculates dynamic support and resistance levels from recent highs and lows. This matches my trading philosophy of focusing on price action, rather than using indicators that lag behind market movements.
Avoiding Indicators
Indicators often introduce delays because they rely on past data. By avoiding them, the bot can react more quickly to market changes, aligning with real-time price movements.
Entry and Exit Criteria
Support and Resistance Levels
The bot calculates dynamic support and resistance levels based on recent highs and lows within specific lookback periods. These levels help determine when to enter and exit trades.
Fibonacci Retracements
Fibonacci levels (50% and 61.8%) are used to identify potential reversal zones, which are the key levels I use when I trade. The bot considers trades when the price approaches these key levels.
Risk Management
Trailing Stops
Initially, I used a fixed stop loss and take profit, but this lacked flexibility and didn't account for market volatility. During a discussion about profit-taking challenges, I realized that implementing a trailing stop mechanism would improve the strategy. The trailing stop adjusts the stop loss as the trade moves in our favor, securing profits dynamically.
Dynamic Position Sizing
I wrote a function that calculates position sizes based on the account balance, allowing for compound growth while managing risk appropriately.
Other Features
I also wrote functions to:
• Check for spike candles
• Count all open positions and limit open positions to 1
• Check for spread and only open positions when the spread is within my accepted parameters
• Limit the max lot size/positionVolume per trade (this was very important as I wrote the code in a way that it compounds)
• Add a cooldown period between trades to remove overtrading and false signals
• Check for spike candles
• Count all open positions and limit open positions to 1
• Check for spread and only open positions when the spread is within my accepted parameters
• Limit the max lot size/positionVolume per trade (this was very important as I wrote the code in a way that it compounds)
• Add a cooldown period between trades to remove overtrading and false signals
Algorithm Development
Initial Iterations
Early versions of the bot used fixed stop losses and take profits, which didn't adapt to market conditions and often led to less-than-ideal exits.
Over several months, I improved the profit-taking mechanism by adding a trailing stop that reflects how I naturally trade. This adjustment allowed for better risk management and profit maximization.
After several iterations and testing on multiple currency pairs and timeframes, I ended up with two static codes developed:
1. Prospera_EURUSD
2. Prospera_AU_EG_EU
Differences in the Implementation of the two Codes
• Prospera_EURUSD: Designed for EURUSD, uses a multi-timeframe approach with Daily (D1) and Hourly (H1) timeframes.
• Prospera_AU_EG_EU: Tailored for AUDUSD and EURGBP, operates on the current chart timeframe.
Currently, the static codes have about 70% profit accuracy. Backtests on AUDUSD from January 2021 to October 2024 showed a profit factor of 1.43 and a recovery factor of 2.33; while the profit factor isn’t exactly the best, the recovery factor was excellent.
Timeframe Adjustments
• Prospera_AU_EG_EU reacts to signals on every tick, allowing for more frequent trading opportunities.
• Prospera_EURUSD generates signals on the daily timeframe and confirms them on the H1 timeframe before executing trades, aiming for higher-quality entries.
• Prospera_EURUSD generates signals on the daily timeframe and confirms them on the H1 timeframe before executing trades, aiming for higher-quality entries.
Multi-Timeframe Analysis
Using higher timeframes in Prospera_EURUSD improves signal reliability by reducing noise and requiring confirmation, leading to more strategic trade entries.
Machine Learning Integration and Data Analysis
Problem Statement
I wanted the bot to be more flexible in different market conditions. One way I did this was by optimizing lookback periods using machine learning, so the bot could change its strategy based on market volatility.
Data Collection
I collected Open-High-Low-Close (OHLC) data from 1990 to 2024 for various currency pairs to ensure comprehensive historical coverage. The data covered different timeframes (1-Day, 4-Hour, 1-Hour, 15-Minute, 5-Minute).
Timeframes Collected:
• 1-Day Data from 01.01.1990 to 06.09.2024
• 4-Hour Data from 01.01.2000 to 06.09.2024
• 1-Hour Data from 01.01.2000 to 06.09.2024
• 15-Minute Data from 06.09.2021 to 06.09.2024
• 5-Minute Data (most recent)
The data was stored in CSV files, and column names were standardized across all timeframes.
Data Preprocessing
The data was cleaned and normalized to remove unnecessary columns and handle any missing values. I also scaled the data using Min-Max scaling and added extra features like the ratio of close price to support and resistance levels.
• Handling Missing Values: I used interpolation and forward-fill techniques to address gaps in the data.
• Normalization: I scaled data using Min-Max scaling to ensure consistency across different time periods and currency pairs.
• Feature Engineering: I added additional columns for close_to_support_ratio and close_to_resistance_ratio, providing the model with insight into how close the price is to support/resistance levels.
After cleaning and normalizing the data, I created lagged features for Close, support, resistance, Trend, and Volume to help the model understand past trends. I also created a signal classification that allows the model to classify signals into "buy, sell, and hold.”
Model Development
80% of the data was used for training, and 20% for testing. During model training, a further 20% of the training data was used for validation.
I built a basic model for each timeframe using two dense layers with ReLU activation and Dropout layers to reduce overfitting. The goal was to predict the optimal lookback periods for each timeframe.
I trained the model for 50 epochs with a batch size of 32, using Mean Absolute Error (MAE) as the main evaluation metric.
Hyperparameter Tuning
I used Bayesian optimization to fine-tune the model’s parameters, like learning rate and batch size, improving the performance across different timeframes. Bayesian optimization helped to find the best hyperparameters for the model for each timeframe.
Final Model Training
After tuning, the models were trained on the different timeframes (1D, 4H, 1H, 15M, 5M). The models were evaluated using metrics like MAPE (Mean Absolute Percentage Error).
• 1D Timeframe: Final Model - MAPE: 8.19%
• 4H Timeframe: Final Model - MAPE: 11.76%
• 1H Timeframe: Final Model - MAPE: 1.38%
• 15M Timeframe: Final Model - MAPE: 9.22%
• 5M Timeframe: Final Model - MAPE: 10.07%
1H timeframe produced the best model with a MAPE of 1.38%. The model also predicted the best lookback periods for each timeframe, which I implemented in the two static codes I wrote.
Visualization
I used Matplotlib to visualize the model’s predictions versus actual values for each timeframe by generating graphs that compare actual closing prices with predicted values across each timeframe.
Here are a few examples comparing the bot’s predicted prices to actual prices, showing how well the model performs across different timeframes:
Here are a few examples comparing the bot’s predicted prices to actual prices, showing how well the model performs across different timeframes:
Backtesting
I tested the bot in a live demo environment, and it followed the strategy rules while adapting to real-time market conditions.
With a capital of $5,000, Prospera_EURUSD generated a total net profit of $34,656.04, with a profit factor of 1.48 on EURUSD.
Prospera_AU_EG_EU produced $63,744.75 net profit with a profit factor of 1.43 on AUDUSD and $21,882.49 net profit with a profit factor of 1.13 on EURGBP.
All of these between January 1, 2021 and October 20, 2024.
Future Enhancements
In the future, I plan to add reinforcement learning so the bot can adapt better to volatility in the market. This will allow the bot to learn from its trades and adjust its strategy to changing market conditions.
Making the Bot More Dynamic
• Adaptive Strategies: Plan to implement algorithms that adjust trading strategies based on real-time market analysis, further improving adaptability.
• Volatility Filters: Introduce mechanisms to detect and adapt to changing volatility levels, enhancing risk management.
Self-Learning Capabilities
• AI and Machine Learning: Incorporate reinforcement learning techniques for the bot to learn from past trades and improve decision-making over time.
• Learning from Trades: By using feedback loops, the bot will learn from past trades and adapt its strategy over time.
• Learning from Trades: By using feedback loops, the bot will learn from past trades and adapt its strategy over time.
Scalability
• Additional Currency Pairs: Expand the bot's use by calibrating it for other markets and currency pairs.
• Cross-Market Analysis: Use relationships between different markets to inform trading decisions.
Conclusion
Summary of Achievements
I built a trading bot that follows sound trading practices with dynamic risk management and machine learning optimization. The bot focuses on price action and support/resistance levels, which led to consistent profits in backtesting.
Lessons Learned
• Technical Skills: I’ve learned a lot about integrating machine learning with MQL5, which has improved my technical and problem-solving skills. This project has helped me apply data analysis and machine learning in a real-world trading environment.
• Analytical Skills: Enhanced my ability to interpret financial data and turn insights into actionable strategies.
• Problem-Solving: Overcame challenges in integrating Python and MQL5 and in optimizing trading algorithms for performance and stability.
Impact on Career Goals
This project demonstrates skills essential for Data Scientist and Data Analyst roles, including data handling, analysis, and applying machine learning. It shows my ability to manage complex projects and apply technical skills to solve real-world problems in finance.