MetaTrader 5 Build 1640: creating and testing custom symbols

What's new in MetaTrader 5

21 July 2017

Terminal

  1. Now it is possible to create custom financial instruments in the terminal. Using the new option, you can create any symbol, configure its settings, import your price data to the symbol and view its charts.

    Creating a Custom Symbol
    Open the symbol management window using the context menu of the "Market Watch" window and click on "Create Custom Symbol":



    A large number of symbol parameters can be configured. The full list of parameters and their description is available in the documentation. You can quickly configure your custom symbol by copying parameters of any similar instrument and modifying them. Select an existing symbol in the "Copy from" field.
    The name of the custom symbol must not match the names of symbols provided by the brokers. If you connect to the server, on which a symbol with the same name exists, the custom symbol will be deleted.
    Commands for importing and exporting parameters are also available here. You can easily share custom symbols or transfer symbols between your terminals. Settings are exported to JSON text files.

    Managing Custom Symbols
    All symbols are displayed in a separate Custom group. If you need to modify or delete a symbol, use the context menu of the list:



    Importing the Price History
    You can import price data to your custom symbol from any text file. Choose a symbol and go to the "Bars" tab.



    In the import dialog, specify the path to the file and set the required parameters:

    • Separator — element separator in a text file.
    • Skip columns and rows — amount of columns (from left to right) and rows (top to bottom) to be skipped during an import.
    • Shift — time shift by hours. The option is used when importing data saved in a different time zone.
    • Use selected only — import only rows highlighted in the row view area. You can highlight rows with your mouse while holding Ctrl or Shift.

    A file with 1-minute bars should have the following format: Date Time Open High Low Close TickVolume Volume Spread. For example;
    2016.06.27    00:01:00    1.10024    1.10136    1.10024    1.10070    18    54000000    44
    2016.06.27    00:02:00    1.10070    1.10165    1.10070    1.10165    32    55575000    46
    2016.06.27    00:03:00    1.10166    1.10166    1.10136    1.10163    13    13000000    46
    2016.06.27    00:04:00    1.10163    1.10204    1.10155    1.10160    23    51000000    41
    You can use data from any existing instrument for your custom symbol. Export data (the option was added in the previous platform version), modify them if necessary, and import the data back.
    The price history is stored in the form of one-minute bars in MetaTrader 5. All other timeframes are created based on these bars. You can also import data of higher timeframes, but charts on lower timeframes will have gaps in this case. For example, if you import one-hour data, one bar per hour will be shown on the M1 chart.
    Price data of custom symbols are saved in a separate Custom directory (not in the directories where data of trade servers are stored):
    C:\Users\[windows account]\AppData\Roaming\MetaQuotes\Terminal\[instance id]\bases\Custom

    Using Custom Symbols
    Use of custom symbols is similar to the use of instruments provided by the broker. Custom symbols are displayed in the Market Watch window; you can open charts of such symbols and apply indicators and analytical objects on them. Custom symbols cannot be traded.

    Testing Strategies on Custom Symbols
    Custom symbols can be used for testing trading robots and indicators in the strategy tester. This allows for optimization of strategies even for the financial symbols a broker is currently unable to provide. You just need to import history correctly and configure the custom symbol properties.



    When calculating the margin and profit, the strategy tester automatically uses available cross rates. Suppose that we have created AUDCAD.custom symbol with the Forex type of margin calculation, and our account currency is USD. In this case, the tester searches for the necessary symbols in the following order based on the Forex symbol name:
    1.     first, the search is performed for the symbols of AUDUSD.custom (for calculating the margin) and USDCAD.custom (for calculating the trade profit) forms
    2.     if any of these symbols is not present, the search is performed for the first symbol corresponding to the necessary currency pairs by name (AUDUSD and USDCAD respectively). For example, AUDUSD.b and NZDUSD.b symbols have been found. This means their rates are to be used to calculate the margin and profit.

    Instruments with other types of margin calculation (Futures and Stock Exchange) require a currency pair to convert the instrument currency into the deposit one. Suppose that we have created a custom symbol with profit and margin currency expressed in GBP, while the deposit currency is CHF. In this case, the search for testing symbols is performed in the following order:
    1. The presence of a trading symbol corresponding to GBPCHF (GBP vs CHF) is checked.
    2. If no such symbol exists, the search is performed for the first trading symbol that corresponds to GBPCHF by its name, for example GBPCHF.b or GBPCHF.def.

    When testing applications using custom instruments, make sure that the trading account has all the necessary currency pairs. Otherwise, the calculation of financial results and margin requirements during testing will not be possible.

    More possibilities will be available in future platform versions
    The development of custom symbols has not completed yet, and more functions will be added in the next builds of the platform. You will be able to import history to custom symbols straight from Expert Advisors, as well as broadcast data (add quotes) of such symbols in real time.

  2. Added filtering of the Time & Sales feature by volume.

    Deals with the volume less than the specified value can be hidden from the Time & Sales table. If this filter is applied, only large deals will appear in the Time & Sales window.

    Double click on the first line in the Time & Sales window, specify the minimum volume in lots, and then click on any other area of ​​the Market Depth. Trades will be filtered, and the current filter value will appear in the volume column header.



    You can also specify the minimum volume using the Time & Sales context menu.

  3. Added an option for binding the Market Depth to an active chart. Every time you switch to a chart of a financial instrument, the same instrument will be automatically enabled in the Market Depth window. So, you will not need to open the Market Depth window for each new symbol.



  4. Fixed refreshing of toolbars after minimizing and maximizing the terminal window.
  5. Fixed generation of position trading history if trade and position tickets overlap.

MQL5

  1. Added an option for profiling MQL5 programs on a price history. This option allows checking the performance of programs without waiting for new ticks.

    When profiling based on real data, the program is launched in a normal chart of the terminal. Many programs, especially indicators, only perform calculations at the arrival of a new tick (OnTick, OnCalculate). Thus, in order to evaluate performance, you have to wait for new ticks in real time. If you test a program using history data, you can immediately provide the required load. Profiling is launched in the visual mode in the Strategy Tester, and you receive a lot of new tick events at a time.



  2. Added support for union. Union is a special data type consisting of several variables sharing the same memory area. Therefore, the union provides the ability to interpret the same bit sequence in two (or more) different ways. Union declaration starts with the 'union' keyword.
    union LongDouble
    {
      long   long_value;
      double double_value;
    };
    Unlike the structure, various union members belong to the same memory area. In this example, the union of LongDouble is declared with long and double type values sharing the same memory area. Please note that it is impossible to make the union store a long integer value and a double real value simultaneously (unlike a structure), since long_value and double_value variables overlap (in memory). On the other hand, an MQL5 program is able to process data containing in the union as an integer (long) or real (double) value at any time. Therefore, the union allows receiving two (or more) options for representing the same data sequence.

    During the union declaration, the compiler automatically allocates the memory area sufficient to store the largest type (by volume) in the variable union. The same syntax is used for accessing the union element as for the structures, i.e. the point operator.
    union LongDouble
    {
      long   long_value;
      double double_value;
    };
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
      {
    //---
       LongDouble lb;
    //--- get and display the invalid -nan(ind) number
       lb.double_value=MathArcsin(2.0);
       printf("1.  double=%f                integer=%I64X",lb.double_value,lb.long_value);
    //--- largest normalized value (DBL_MAX)
       lb.long_value=0x7FEFFFFFFFFFFFFF;
       printf("2.  double=%.16e  integer=%I64X",lb.double_value,lb.long_value);
    //--- smallest positive normalized (DBL_MIN)
       lb.long_value=0x0010000000000000;    
       printf("3.  double=%.16e  integer=%.16I64X",lb.double_value,lb.long_value);
      }
    /*  Execution result
        1.  double=-nan(ind)                integer=FFF8000000000000
        2.  double=1.7976931348623157e+308  integer=7FEFFFFFFFFFFFFF
        3.  double=2.2250738585072014e-308  integer=0010000000000000
    */

  3. Added automatic generation of an implicit copy operator for the objects of structures and classes. Now, the compiler automatically creates copy operators, which allows writing simple entries for objects, such as b=a:
    class Foo
      {
       int               value;
    public:
       string Description(void){return IntegerToString(value);};
       //--- default constructor
                         Foo(void){value=-1;};
       //--- parameterized constructor   
                         Foo(int v){value=v;};
      };
    //+------------------------------------------------------------------+
    //|  structure containing Foo type objects                           |
    //+------------------------------------------------------------------+
    struct MyStruct
      {
       string            s;
       Foo               foo;
      };
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
      {
    //---
       MyStruct a,b;
       Foo an_foo(5);
       a.s="test";
       a.foo=an_foo;
       Print("a.s=",a.s," a.foo.Description()=",a.foo.Description());
       Print("b.s=",b.s," b.foo.Description()=",b.foo.Description());
    //---
       Print("b=a");
       b=a;
    //---
       Print("a.s=",a.s," a.foo.Description()=",a.foo.Description());
       Print("b.s=",b.s," b.foo.Description()=",b.foo.Description());
    /*
       Execution result;
       a.s=test a.foo.Description()=5
       b.s= b.foo.Description()=-1
       b=a
       a.s=test a.foo.Description()=5
       b.s=test b.foo.Description()=5
    */
      }
    Memberwise copying of objects is performed in the implicit operator.

    • If a member is an object, the corresponding copying operator for this object is called.
    • If a member is an array of objects, the receiving array is increased or reduced to the require size using ArrayResize before calling the appropriate copying operator for each element.
    • If a member is an array of simple types, the ArrayCopy function is used for copying.
    • If a member is a pointer to an object, the pointer is copied rather than the object to which it points.

    If necessary, you can override the behavior and create your own option instead of an implicit copy operator, using overloading.

  4. Optimized memory use when accessing the price history from Expert Advisors using the Copy* function. Memory consumption will be reduced manifold when working with large amounts of data.

  5. Now, the TimeToStruct function returns a boolean value, allowing to check the success of conversion of datetime to MqlDateTime.
  6. Added ban to use the FileWriteStruct and FileReadStruct functions for structures containing strings, dynamic arrays, object and pointers.
  7. The following response codes have been added:

    • TRADE_RETCODE_REJECT_CANCEL — the request to activate a pending order is rejected, the order is canceled
    • TRADE_RETCODE_LONG_ONLY — the request is rejected, because the rule "Only long positions are allowed" is set for the symbol
    • TRADE_RETCODE_SHORT_ONLY — the request is rejected, because the rule "Only short positions are allowed" is set for the symbol
    • TRADE_RETCODE_CLOSE_ONLY — the request is rejected, because the rule "Only closing of existing positions is allowed" is set for the symbol

  8. Added new return value of the SymbolInfoInteger function with the SYMBOL_ORDER_MODE parameter. SYMBOL_ORDER_CLOSEBY — permission of a Close By operation, i.e. closing a position by an opposite open position.
  9. The SYMBOL_CUSTOM boolean property has been added to the ENUM_SYMBOL_INFO_INTEGER enumeration. The property allows finding out if the symbol is custom. Use the SymbolInfoInteger function to get the property.
  10. Now it is possible to obtain the reason for the creation of an order, deal or position.

    New properties


    Order, deal and position creation reasons
    Three variables have been added for obtaining the reasons for the creation of trading operations:

    ENUM_POSITION_REASON ENUM_DEAL_REASON ENUM_ORDER_REASON Reason description
    POSITION_REASON_CLIENT DEAL_REASON_CLIENT ORDER_REASON_CLIENT The operation was executed as a result of activation of an order placed from a desktop terminal
    POSITION_REASON_MOBILE DEAL_REASON_MOBILE ORDER_REASON_MOBILE The operation was executed as a result of activation of an order placed from a mobile application
    POSITION_REASON_WEB DEAL_REASON_WEB ORDER_REASON_WEB The operation was executed as a result of activation of an order placed from the web platform
    POSITION_REASON_EXPERT DEAL_REASON_EXPERT ORDER_REASON_EXPERT The operation was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script
    - DEAL_REASON_SL ORDER_REASON_SL The operation was executed as a result of Stop Loss activation
    - DEAL_REASON_TP ORDER_REASON_TP The operation was executed as a result of Take Profit activation
    - DEAL_REASON_SO ORDER_REASON_SO The operation was executed as a result of the Stop Out event
    - DEAL_REASON_ROLLOVER - The deal was executed due to a rollover
    - DEAL_REASON_VMARGIN - The deal was executed after charging the variation margin
    - DEAL_REASON_SPLIT - The deal was executed after the split (price reduction) of a stock or another asset, which had an open position during split announcement

  11. Optimized synchronization and access to the tick history.
  12. Fixed returning of ticks to the statistic array in the CopyTicksRange function. In earlier versions, 0 ticks were always returned in this case.
  13. Various fixes have been made in the Fuzzy Logic Library.

Signals

  1. : Fixed opening of a signal from the website when there is no trading account connection.

Tester

  1. Optimized and accelerated work with the history of orders and deals. Operation speed will be increased manifold when working with large amounts of data (tens of thousands of history entries).
  2. Fixed calculation of position holding time in the testing report.

MetaEditor

  1. Fixed the display of the contents of static class member arrays in the debugger.
  2. Added a list of breakpoints in the debugged program. The list can be opened using the context menu of the Debug tab:



    To jump to a breakpoint, double-click on it.


Updated documentation.