├── General differences.md └── README.md /General differences.md: -------------------------------------------------------------------------------- 1 | # General differences between MQL4 and MQL5 2 | 3 | In terms of code grammar, there are very few differences. They amount to making sure `#property strict` is specified; using `input` variables for user settings; and making sure you initialize your variables with a default value. 4 | 5 | ### Make sure `#property strict` is specified in each source file 6 | 7 | Inserting `#property strict` on the top of each file ensures MQL4 will run in "Strict" mode, which enforces standards more closely to MQL5 rather than pre-2014 MQL4. Without this line, unexpected behavior will occur in MT4. 8 | 9 | For programs written in the pre-2014 MQL4 dialect, inserting this line will often spout lots of errors because of the different coding practices. This should be mitigated by following good practices found in this guide and generally. 10 | 11 | This line is usually inserted if you create a file under MetaEditor 4, but it is not inserted if you use MetaEditor 5, so make sure this line is present in each source file. 12 | 13 | ### For settings, use `input` variables, not `extern` variables 14 | 15 | Though valid in MQL4, `extern bool var;` became invalid for user settings in MQL5 starting 2017. MQL5 requires that you use `input bool var;` or else the settings window does not display. 16 | 17 | [According to the MQL5 docs](https://www.mql5.com/en/docs/basis/variables/externvariables), the `extern` variable is intended as a shared variable across source files tied together with `#include`. It happens to be MT4 practice to use `extern` variables as user settings, but MT5 discontinued this practice. That said, `extern` variables still work in MQL5 under their intended capacity. 18 | 19 | `input` variables can only be set once by the user and cannot be changed during runtime. **If you use `extern` variables as user settings, you should verify whether you change those `extern` variables to new values during runtime:** 20 | 21 | * If you do not, it is safe to search-replace the `extern` variables to `input` variables. 22 | * If you do change `extern` variables, you can have separate `input` variables, then copy the values to your current `extern` variables during `OnInit`. 23 | 24 | ### Variables must be initialized with a default value 25 | 26 | In MQL4, if you declare a variable, its value is implicitly initialized to 0 or equivalent. Therefore, you can write `int startVal;` without specifying the value. This fails in MQL5 because MT5 does not initialize variables for you -- you must initialize all variables with a default value: `int startVal = 0;`. 27 | 28 | By initializing the variable, subsequent logic will work as expected. 29 | 30 | ```mql5 31 | #property strict 32 | 33 | void OnStart() 34 | { 35 | // Wrong 36 | int startVal; 37 | 38 | Print("startVal: " + startVal); 39 | // MT4 output - "startVal: 0" 40 | // MT5 output - "startVal: -382372343" (random value from memory) 41 | 42 | // Right 43 | int startVal5 = 0; 44 | 45 | Print("startVal5: " + startVal5); 46 | // MT4 output - "startVal5: 0" 47 | // MT5 output - "startVal5: 0" (correct value) 48 | } 49 | ``` 50 | 51 | This is based on C++ rules where variables needed to be initialized or else a latent value from memory is used. 52 | 53 | Though C++ rules dictate that structs and arrays must also be initialized by default values, MQL5 does not require this. For peace of mind, you may choose to initialize structs and arrays should this rule change: 54 | 55 | * Structs - `MqlTradeRequest request = {0};` 56 | * Arrays - `int arr[5]; ArrayInitialize(arr, 0);` 57 | 58 | ### Array series direction must be declared explicitly 59 | 60 | Array series direction (newest to oldest order) needs to be initialized for the `OnCalculate` method with custom indicators by calling `ArraySetAsSeries`. 61 | 62 | In MQL4, you can access `open[]`, `close[]`, etc., from newest to oldest order because it is implicit that `ArraySetAsSeries` is true for the bar data. MQL5 does not assume this, so you must call `ArraySetAsSeries` explicitly to access data from newest to oldest order. 63 | 64 | ```mql5 65 | #property strict 66 | 67 | int OnCalculate(const int rates_total, 68 | const int prev_calculated, 69 | const datetime &time[], 70 | const double &open[], 71 | const double &high[], 72 | const double &low[], 73 | const double &close[], 74 | const long &tick_volume[], 75 | const long &volume[], 76 | const int &spread[]) 77 | { 78 | // Wrong - not calling ArraySetAsSeries 79 | 80 | Print("Times: " + time[0] + ", " + time[1] + ", " + time[2]); 81 | // MQL4 output - "Times: 2017.08.04 00:00, 2017.08.03 00:00, 2017.08.02 00:00" 82 | // MQL5 output - "Times: 2001.06.19 00:00, 2001.06.20 00:00, 2001.06.21 00:00" (oldest to newest order) 83 | 84 | // Right - call ArraySetAsSeries explicitly 85 | ArraySetAsSeries(time, true); 86 | 87 | Print("Times: " + time[0] + ", " + time[1] + ", " + time[2]); 88 | // MQL4 output - "Times: 2017.08.04 00:00, 2017.08.03 00:00, 2017.08.02 00:00" 89 | // MQL5 output - "Times: 2017.08.04 00:00, 2017.08.03 00:00, 2017.08.02 00:00" (newest to oldest order) 90 | 91 | return rates_total; 92 | } 93 | ``` 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MQL4 to MQL5 2 | 3 | This guide will teach you how to port your MQL4 code so that it works in both MT4 and MT5. The goal is to allow you to use the same codebase for both versions and cross-compile between the two. 4 | 5 | ## Page Navigation 6 | 7 | * [General differences between MQL4 and MQL5](https://github.com/mazmazz/Mql4ToMql5/blob/master/General%20differences.md) 8 | 9 | # Why port your project to MQL5? 10 | 11 | ## 1. It's not as hard as you think 12 | 13 | Believe it or not, most basic logic and structure from an MQL4 project will compile as-is in MQL5. You just need to know the differences and how to apply them -- most of them are minor, and just a few are significant. And no, OOP is not required. 14 | 15 | Once you know the rules, it's straightforward to write your code so that it cross-compiles identically with MQL4 and MQL5. You can write changes just once and they work the same in both versions. The version-specific code is kept minimal and easy to section off from the main code. This guide will cover what changes you'll need to make. 16 | 17 | ## 2. MT5 is practically the same as MT4 18 | 19 | This wasn't always true. You may have heard that trading in MT5 is restrictively different from MT4 because it only allowed for one trade direction per instrument and it forced FIFO. 20 | 21 | **As of Spring 2016, this adage has been false.** MT5 has been retooled with *"Hedging Mode"*, which makes trading work identically to MT4: it allows for multiple trades per symbol and FIFO is not enforced. The interface to execute and review trades is practically the same, as is the charting. 22 | 23 | While the broker does need to enable this mode, it is pretty easy to find brokers who use it. Hedging should be the de facto mode, going forward. 24 | 25 | ## 3. MT5 is better than MT4 26 | Besides being visually similar, MT5 is more stable than MT4 and has both under-the-hood improvements and new features. 27 | 28 | In terms of user-facing features, a lot of thought was put in how to re-organize certain features. For instance: 29 | 30 | * MT5's [Depth of Market widget](https://www.metatrader5.com/en/terminal/help/depth_of_market) is an actual depiction of Depth of Market, compared to MT4's [lot-sizing order tool](https://www.metatrader4.com/en/trading-platform/help/overview/depth_of_market) that's erroneously called "Depth of Market". 31 | * In MT5's [Symbols window](https://www.metatrader5.com/en/releasenotes/terminal/1427), you have easy access to both Bar and Tick history that is searchable by datetime, whereas MT4's equivalent [History Center](https://www.metatrader4.com/en/trading-platform/help/service/history_center) affords no such access to specific times. 32 | 33 | But most importantly, _**MT5 has an overhauled backtester that is actually competent!**_ A few examples: 34 | 35 | * Since Spring 2016, MT5 uses **real ticks and real spreads** downloaded from the broker's server to run the backtest, whereas MT4 simulates ticks artificially and does not model spreads (you had to resort to hacks for these features.) 36 | * MT5 allows you to backtest **multi-symbol baskets** such that symbol interplay is accurately modeled and the results show the basket total. MT4 can only process one symbol at a time, such that baskets have to be tested separately and without symbol interplay. 37 | * Optimizer tests in MT5 can be run in parallel per processor thread, and even on other PCs via LAN. More impressively, MetaQuotes runs a cloud service allowing access to thousands of test servers, such that days-long optimizing can be had for under a half hour. 38 | 39 | By comparison, MT4's backtester is primitive and without competent accuracy, so its negative reputation is well deserved. It's understandable why forward testing is rule of law in MT4 communities, but in the quant world, backtesting and statistics are king to deploying evidence-based strategies rapidly. 40 | 41 | MT5's backtester goes a long way towards accuracy and rapid iteration. Frankly, it's a joy to get comparably accurate year-long results in under an hour compared to forward testing the same results for weeks and months on end. 42 | 43 | [![MT5 backtester](https://thumbs.gfycat.com/EmbarrassedVigorousEarthworm-size_restricted.gif)](https://gfycat.com/EmbarrassedVigorousEarthworm) 44 | 45 | ## In sum... 46 | 47 | It's a shame so far that MT5 has low adoption because its improvements really are welcome. MT5 is kind of a hidden gem, but it really shouldn't be hidden. If many people can write EAs and indicators that work with both MetaTrader versions, hopefully more brokers will offer MT5. 48 | 49 | # What you need to know for your code 50 | 51 | ## 1. Cross-compiling between MQL4 and MQL5 is straightforward 52 | 53 | MQL4 and MQL5 are shared enough that you can use the exact same codebase to compile between the two versions. 54 | 55 | For instance, many MQL4 function calls have an MQL5 equivalent that's valid in both versions, so it makes much sense to make calls in the MQL5 method so that they work universally. 56 | 57 | For cases where the MQL5 logic must be different, you can use the preprocessor directives `#ifdef __MQL4__` and `#ifdef __MQL5__` to section off the logic. Only in specific cases is version-specific code necessary, and most other code can be written as valid for both versions. 58 | 59 | ## 2. OOP is not required 60 | 61 | It's a myth that MQL5 programs must be structured in an object-oriented format. While OOP is good practice in general, MQL5 works just fine by solely using the event calls `OnStart`, `OnTimer`, `OnTick`, `OnCalculate`, etc. They even work the same as the old MQL4 equivalents like `start`, `init`, etc. -- just a few different namings and arguments. And you can use top-level functions and global variables as much as you like -- just like the typical MQL4 program. 62 | 63 | ## Websites 64 | 65 | For more details on a certain topic, you can view these links: 66 | 67 | * [MQL4 to MQL5 Equivalency Tables](https://www.mql5.com/en/articles/81) - Contains a table of MQL4 and MQL5 method and constant equivalents -- thorough but missing certain areas like Orders 68 | * [MQL5 Docs - Moving from MQL4 to MQL5](https://www.mql5.com/en/docs/migration) - A brief discussion on porting considerations 69 | 70 | Next, [view this page to learn about MQL4 and MQL5 differences](https://github.com/mazmazz/Mql4ToMql5/blob/master/General%20differences.md). 71 | --------------------------------------------------------------------------------