Libraries: Symbol - page 2

 
Stanislav Korotky:

We should add something like:

Otherwise sometimes only properties are needed and bars are not.

All the methods of the class are public. So to clone only properties call CloneProperties().

 

The library and example of use have been updated.

Пример

When running a backtest on crosses, the tester pulls not only the main symbol, but also an auxiliary symbol, which allows converting the profit currency of the main symbol to the account currency. Pulling the auxiliary symbol, generating its ticks and synchronising them with the main symbol takes up such precious computing resources (and time) in Single Run and, especially, Optimisation modes.


However, such precision is almost always unnecessary. Therefore, I would like to bypass this obsession/imperfection of the MetaTrader 5 tester. In MetaTrader 4 it is easy to do this - there is a possibility to change the account currency right in the tester. MetaTrader 5 does not have such an option.

The demo script shows a way to bypass this limitation of the tester - to remove unnecessary calculations. To do this, a copy of the symbol for backtest is created, but the currency of profit/margin is set equal to the account currency. That is, there will be no need to reconvert the trade results. And the profit will actually be calculated in pips, which can be very clear in some situations.

// Create a copy of the symbol to speed up the Tester
#property script_show_inputs

#include <Symbol.mqh>

void OnStart()
{
  const SYMBOL Symb("TESTER_" + _Symbol); // Created a symbol

  if (Symb.IsExist()) // If the symbol is created
  {
    Symb = _Symbol; // Copied all properties and bar history (+ tick history if custom) from the main symbol - clone

    // Make the currencies of the symbol the currency of the account
    Symb.SetProperty(SYMBOL_CURRENCY_PROFIT, AccountInfoString(ACCOUNT_CURRENCY));
    Symb.SetProperty(SYMBOL_CURRENCY_MARGIN, AccountInfoString(ACCOUNT_CURRENCY));

    if (Symb.On()) // Included in the Market Watch
      ChartOpen(Symb.Name, PERIOD_CURRENT); // Opened a new symbol chart
  }
}


Result


In this way, a free acceleration of the Tester/Optimiser is achieved.


ZЫ I measured it thoroughly on EURGBP. The time gain is ~2 times. The trades are fully matched. Free of charge indeed!

 

The following remark concerns not only the library.


If you need to change some properties of a custom symbol, in some cases it should be done BEFORE importing quotes.

Therefore, for reliability of the result, I strongly recommend to set all properties of the symbol first, and only then to import.

For example, if you want to set SYMBOL_TRADE_TICK_VALUE and SYMBOL_TRADE_TICK_SIZE, it should be done before importing ticks/bars.

 

In MT5-tester, as a rule (forex, for example), limit orders have positive slippage, which leads to self-deception (sometimes even in the form of tester grails on real ticks!).



But there is a way to bypass this feature of the Tester. Below is a detailed instruction on how to do it.


1. If the original symbol (open chart) is not custom or the account is hedged, run this script on the symbol chart

#include <Symbol.mqh>

void OnStart()
{
  const SYMBOL Symb(_Symbol + "_Custom"); // Created a symbol

  if (Symb.IsExist()) // If the symbol is created
  {
    Symb = _Symbol;   // Copied all properties and bar history (+ tick history if custom) from the main symbol - clone

    if (Symb.On())    // Included in the Market Watch
      ChartOpen(Symb.Name, PERIOD_CURRENT); // Opened a new symbol chart
  }
}


You will get this picture



2. If the account is hedged (the word Hedge is present in the Terminal window title bar), go to any netting account (for example, MetaQuotes-Demo) and reload the Terminal.

3. run this script on the current chart

// Creating a copy of the symbol to speed up the Tester with the possibility to disable slippage of limit orders
#property script_show_inputs

#include <Symbol.mqh>

input bool OrderLimitSlippage = false;

void OnStart()
{
  const SYMBOL Symb("TESTER_" + _Symbol); // Created a symbol

  if (Symb.IsExist()) // If the symbol is created
  {
    // https://www.mql5.com/ru/forum/212096/page2#comment_7017794
// Symb = _Symbol; // Copy all properties and bar history (+ tick history if custom) from the main symbol - clone

    Symb.CloneProperties(); // Copy all properties from the main symbol

    // Make the currencies of the symbol the currency of the account
    Symb.SetProperty(SYMBOL_CURRENCY_PROFIT, AccountInfoString(ACCOUNT_CURRENCY));
    Symb.SetProperty(SYMBOL_CURRENCY_MARGIN, AccountInfoString(ACCOUNT_CURRENCY));
    Symb.SetProperty(SYMBOL_CURRENCY_BASE, AccountInfoString(ACCOUNT_CURRENCY));
    
    int Answer = IDNO;
    
    // Remove slippage of limit orders
    // https://www.mql5.com/ru/forum/212096/page2#comment_7018318
    if (!OrderLimitSlippage &&
        (((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE) != ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) ||
        ((Answer = MessageBox("You will need to change the account type to netting.\nDo you agree to disable limit order slips?", __FILE__, MB_YESNOCANCEL | MB_ICONQUESTION)) == IDYES)))
    {
      Symb.SetProperty(SYMBOL_TRADE_EXEMODE, SYMBOL_TRADE_EXECUTION_EXCHANGE);
      Symb.SetProperty(SYMBOL_TRADE_CALC_MODE, SYMBOL_CALC_MODE_EXCH_FUTURES);
      
      // To calculate the profit
      Symb.SetProperty(SYMBOL_TRADE_TICK_VALUE, 1);
      Symb.SetProperty(SYMBOL_TRADE_TICK_SIZE, Symb.GetProperty(SYMBOL_POINT));
    }
    
    if ((Answer != IDCANCEL) && (Symb.CloneHistory() > 0) && Symb.On()) // Copied bar history (+ tick history if custom) from the main symbol
      ChartOpen(Symb.Name, PERIOD_CURRENT); // Opened a new symbol chart 
  }
}



3. Select the received custom symbol in the Tester


Now limit orders will not slide!

 

Forum on trading, automated trading systems and testing trading strategies

Errors, bugs, questions

fxsaber, 2018.02.14 14:41 pm.

Ugly bug not Terminal, but Platform MT5
#include <MT4Orders.mqh> // https://www.mql5.com/en/code/16006

#define Bid SymbolInfoDouble(_Symbol, SYMBOL_BID)
#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

void OnStart()
{
  OrderSend(_Symbol, OP_BUY, 1, Ask, 100, 0, Bid);
  
// OrderSend(_Symbol, OP_BUYLIMIT, 1, Ask, 100, 0, 0);
}

Running on MQ-Demo on some slow moving symbol. For example, EURHUF.

The script opens a BUY position with TP = Bid. I.e. the position should be closed immediately. But TP will be checked for compliance with the acceptance condition only on the next tick!

No instant closing of the position will take place until the next tick. Moreover, if the next tick has Bid < TP, TP will remain without acceptance.


The same applies to limit orders (commented line). In Tester, the situation is similar.

On the highlighted, it should be said, because in the previous post there is this

Forum on trading, automated trading systems and testing trading strategies.

Libraries: Symbol

fxsaber, 2018.04.06 09:21 pm.

2. If the account is hedged (the word Hedge is present in the Terminal window title bar), go to any netting account (e.g. MetaQuotes-Demo) and reload the Terminal.

and not everyone will notice that limit orders at the current price on exchange symbols of netting accounts will be executed (and in the Tester) immediately, without waiting for the next tick.


Note, it is not just the stock symbol that is important, but the netting account as well. For example, you can take a MOEX symbol on a Hedge-MQ-Demo, but it will not execute the same way (and in the Tester) as on the same Netting-MQ-Demo.

This is one of the reasons why backtests on the same completely identical MOEX-symbols can be different, depending on the account type.


ZЫ I'm talking to myself....

 
fxsaber:

ZY I'm talking to myself...

No, I just have nothing to add.

It's a pity that to realise normal triggering of orders you need to dance with tambourines.

 
Andrey Khatimlianskii:

It is a pity that to realise normal triggering of orders you need to dance with tambourines.

I have changed the instructions, simplifying the dances considerably. For example, on netting everything is done in one click - launching the script.

 

I applied a simple filter to real ticks, which throws out > 90% of the information in the lightest case. The stronger the filter, the coarser the backtest result.

But it was interesting how the weakest filter affects the result and speed.


Quality.

Was

final balance 10007242.00 EUR
TESTER_Censored,M1: 6589567 ticks, 60353 bars generated. Environment synchronized in 0:00:00.031. Test passed in 0:00:05.101 (including ticks preprocessing 0:00:00.874).
TESTER_Censored,M1: total time from login to stop testing 0:00:05.132 (including 0:00:00.031 for history data synchronization)
476 Mb memory used including 27 Mb of history data, 192 Mb of tick data


Became

final balance 10007246.00 EUR
FILTER_Censored,M1: 402622 ticks, 50887 bars generated. Environment synchronized in 0:00:00.030. Test passed in 0:00:00.516 (including ticks preprocessing 0:00:00.078).
FILTER_Censored,M1: total time from login to stop testing 0:00:00.546 (including 0:00:00.030 for history data synchronization)
314 Mb memory used including 27 Mb of history data, 64 Mb of tick data


Speed

Was

OnTesterInit
i = 0 Pass = 0 OnTester = 3.881 s.: Count = 6589567, 1697904.4 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 1 Pass = 1 OnTester = 3.893 s.: Count = 6589567, 1692670.7 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 2 Pass = 2 OnTester = 3.898 s.: Count = 6589567, 1690499.5 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 3 Pass = 3 OnTester = 3.842 s.: Count = 6589567, 1715139.8 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 4 Pass = 4 OnTester = 3.912 s.: Count = 6589567, 1684449.6 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
iMin = 3 Results[iMin] = 3.842 s.
iMax = 4 Results[iMax] = 3.912 s.
Amount = 5 Mean = 3.885 s. - 84.80%
OnTesterDeinit


Was

OnTesterInit
i = 0 Pass = 0 OnTester = 0.264 s.: Count = 402622, 1525083.3 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 1 Pass = 1 OnTester = 0.264 s.: Count = 402622, 1525083.3 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 2 Pass = 2 OnTester = 0.264 s.: Count = 402622, 1525083.3 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 3 Pass = 3 OnTester = 0.266 s.: Count = 402622, 1513616.5 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 4 Pass = 4 OnTester = 0.306 s.: Count = 402622, 1315758.2 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
iMin = 0 Results[iMin] = 0.264 s.
iMax = 4 Results[iMax] = 0.306 s.
Amount = 5 Mean = 0.273 s. - 29.28%
OnTesterDeinit


Result

According to real ticks, the number of ticks decreased by 16 times (the lightest filter), the speed of Optimisation increased by 14 times, the quality did not suffer at all (the analysis that was not included here). Of course, this can be done only when writing the TS in a certain way. In particular, with the absence of bar analysis.

The previous free universal acceleration gave only a twofold increase. The current one is also free (the quality does not suffer), but less universal. However, the return is more than an order of magnitude. Now I optimise TC only in this way. No mistake.


SZY

At the same time, a short check of this implementation (only bar spread calculated differently).

Forum on trading, automated trading systems and testing trading strategies.

Scripts: ThirdPartyTicks

Automated-Trading, 2018.03.16 09:35 pm.

Баровая история создается с учетом минимальных потерь качества при переходе от режима тестирования "Каждый тик на основе реальных тиков" к "Только цены открытия" - ТС на лимитных ордерах;

Two modes are compared: "All ticks" and "OHLC M1".


All ticks

final balance 10006150.00 EUR
TESTER4_Censored,M1: 6576734 ticks, 60353 bars generated. Test passed in 0:00:04.587 (including ticks preprocessing 0:00:00.343).
394 Mb memory used including 27 Mb of history data, 128 Mb of tick data


OHLC M1

final balance 10006119.00 EUR
TESTER_Censored,M1: 240366 ticks, 60353 bars generated. Test passed in 0:00:00.359 (including ticks preprocessing 0:00:00.031).
306 Mb memory used including 27 Mb of history data, 64 Mb of tick data


Backtest quality is the same, the performance of the second variant in a single run is 12 times better.

 

For a non-programmer, do these scripts need to be written into an Expert Advisor programme?

It is very tempting to speed up optimisation by 12 times.

Will there be such acceleration when optimising by opening points?

 
Aleksey Panfilov:

For a non-programmer, do these scripts need to be written into an EA programme?

It is very tempting to speed up optimisation by 12 times.

Will there be such acceleration when optimising by opening points?

Unfortunately, it is very hard to explain all the aspects of this process. It would take an article, probably. Therefore, it will not be possible to explain it clearly and briefly.