3. MQL4 dla początkujących. Część III.

3.1. Zewnętrzne zmienne typu input i extern

Jeśli pracowałeś już w terminalu MetaTrader 4 to pewnie zauważyłeś, że przy uruchomieniu jakiegokolwiek standardowego wskaźnika pojawia się okienko, gdzie można zmieniać wejściowe parametry tego wskaźnika. Na poniższym obrazku widać jak wygląda takie okienko dla Stochastic, gdzie użytkownik ma możliwość zmienić jego parametry.

Rys. 1. Wejściowe parametry wskaźnika Stochastic.


W zakładce Wpisz parametry po lewej stronie widzimy nazwy parametrów tego wskaźnika (zielony prostokąt), a po prawej stronie ich domyślne wartości (niebieski prostokąt). Jest to zdecydowanie lepszy sposób na zmianę wejściowych parametrów programu niż grzebanie w kodzie źródłowym. Z drugiej strony przy optymalizacji automatycznej strategii tester strategii powinien mieć możliwość w zaprogramowany sposób zmieniać jej parametry. Może być też i tak, że mamy fajny program tylko jako plik skompilowany (*.ex4) i nie ma możliwości coś zmienić w kodzie źródłowym.

Istnieje prosty sposób aby osiągnąć taki efekt w każdym naszym programie. Pokażę to na przykładzie poniższego skryptu.

Kod 1
#property strict
#property script_show_inputs

//--- inicjalizacje zmiennych jako zewnętrzne parametry skryptu
input int    age      = 25;
input double height   = 1.95;
input string dog_name = "Puszek Okruszek";

//--- główna funkcja skryptu
void OnStart()
  {
  }

Widzimy tu dobrze już nam znaną dyrektywę #property , która występuje tu dwa razy. W pierwszej linijce obok niej jest właściwość strict, a w drugiej script_show_inputs i właśnie ta druga komenda jest odpowiedzialna za pojawienie się okienka jak na rys. 1 i jest stosowana tylko w skryptach. Ani w wskaźnikach ani w strategiach automatycznych nie trzeba jej pisać.

Dalej utworzono trzy zmienne, gdzie najpierw zapisano modyfikator input, potem typ i nazwę zmiennej. Dalej po znaku = każdej zmiennej przypisano odpowiednie wartości.


Zewnętrzne parametry należy inicjalizować przed główną funkcją programu.

Na poniższym rysunku widać, że po uruchomieniu tego skryptu też pojawi się okienko.

Rys. 2. Wejściowe parametry skryptu.


W kolumnie Zmienne widzimy ich oryginalne nazwy (rys. 2). Jako twórca tego skryptu znam ich przeznaczenie i można też intuicyjnie się domyśleć o ich roli w programie. Ale gdybym użył innych nazw, np. A, B i C to ja bym nadal wiedział o co chodzi, ale inny użytkownik nie koniecznie. Z drugiej strony jeśli napiszę program, zawierający dużo zewnętrznych parametrów to i ja mogę się wśród nich pogubić. Istnieje przyjaźniejszy sposób poinformowania użytkownika o roli każdego parametru - po prawej stronie od niego napisać komentarz jednowierszowy (kod 2).

Kod 2
#property strict
#property script_show_inputs

//--- inicjalizacje zmiennych jako zewnętrzne parametry skryptu
input int    age      = 25;                // Mój wiek
input double height   = 1.95;              // Mój wzrost
input string dog_name = "Puszek Okruszek"; // Imię pieska sąsiadki

//--- główna funkcja skryptu
void OnStart()
  {
   Print("Mam " , age , " lat.");
   Print("Mam " , height , " cm zwrostu.");
   Print("Imię pieska sąsiadki " , dog_name , ".");
  }

W tym kodzie po prawej stronie od każdej zmiennej, po // zapisano komentarz, a w ciele głównej funkcji OnStart() umieszczono trzy funkcje Print(), które wyświetlą odpowiednie informacje w logach terminala (rys. 3).

Rys. 3. Wejściowe parametry skryptu z komentarzami.


Teraz to wygląda o wiele lepiej . Po kliknięciu na OK w logach terminala w zakładce Strategie zobaczymy wynik działania skryptu.

Rys. 4. Wynik działania skryptu.

W zakładce Strategie w kolumnie Czas widzimy datę i dokładny czas pojawienia się każdego wpisu. W kolumnie Wiadomość począwszy od dołu idą:

  • Script Test EURUSD,H4: loaded successfully - skrypt z powodzeniem został uruchomiony na wykresie notowań EURUSD o przedziale czasowym 4 godzina (H4);
  • Test EURUSD,H4 inputs: age=25; height=1.95; dog_name=Puszek Okruszek; - oryginalne nazwy parametrów jak w kodzie źródłowym i ich domyślne wartości;
  • Test EURUSD,H4: initialized - czas inicjalizacji skryptu;
  • Test EURUSD,H4: Mam 25 lat. - komunikat wyświetlony przez pierwszą funkcję Print();
  • Test EURUSD,H4: Mam 1.95 cm wrostu. - komunikat wyświetlony przez drugą funkcję Print();
  • Test EURUSD,H4: Imię pieska sąsiadki Puszek Okruszek. - komunikat wyświetlony przez trzecią funkcję Print();
  • Test EURUSD,H4: uninit reason 1 – przyczyna zakończenia działania skryptu. W tym przypadku nie ma błędu, "reason 1” oznacza, że powodem zakończenia jest usunięcie programu z wykresu notowań;
  • Script Test EURUSD,H4: removed – usunięcie skryptu.

W celu ogłoszenia zmiennej jako parametr zewnętrzny zamiast input można także stosować modyfikator extern. Jedyna różnica między nimi jest taka, że zmienna ogłoszona jako input staje się stałą i dostępna jest tylko do odczytu. Z kolei zmienna z modyfikatorem extern może być zmieniana w trakcie działania programu.

Jeśli spróbujesz skompilować poniższy kod, gdzie skrypt będzie próbował age zmienić na 18, to kompilator wyświetli błąd: 'age' - constant cannot be modified i ten skrypt nie będzie działać w MetaTrader 4.

Kod 3
#property strict
#property script_show_inputs

input int age = 25;  // Mój wiek

//---
void OnStart()
  {
   age++;  /* dodanie 1 do zmiennej age,
              kompilator wykryje błąd,
              ponieważ nie można zmienić
              zewnętrzną zmienną typu input */

   Print("Za rok będę miał " , age , " lat.");
  }

Jeśli będziesz chciał mieć możliwość zmiany wartości zewnętrznego parametru, to zamiast input zastosuj extern. Na przykład w poniższym kodzie age znowu spróbujemy zamienić na 18 i to nam się uda.

Kod 4
#property strict
#property script_show_inputs

extern int age = 25; // Mój wiek

//---
void OnStart()
  {
   age++;  /* dodanie 1 do zmiennej age,
              nie ma błędu, ponieważ można
              zmienić zewnętrzną zmienną typu extern */

   Print("Za rok będę miał " , age , " lat.");
  }

Parę rzeczy, o których należy pamiętać:

Tablice nie mogą być inicjalizowane jako input lub extern.
Długość komentarza dla zmiennych input lub extern nie może być większa niż 63 symboli.

W przypadku gdyby wartość zewnętrznego parametru chciałbyś przechowywać w tablicy, to ten parametr należy po prostu skopiować do odpowiedniego elementu tablicy (kod 5).

Kod 5
#property strict
#property script_show_inputs

//--- parametry input
input string Friend_A = "Bartek"; // Konkretny kolega z pracy
input string Friend_B = "Kasia";  // Miła koleżanka z pracy
input string Friend_C = "Michał"; // Sąsiad
input string Friend_D = "Magda";  // Sąsiadka
input string Friend_E = "Benek";  // Fajny gość

//--- deklaracja tablicy składającej się z 5 elementów
string Friend_name[5];

void OnStart()
  {
   //--- kopiowanie zewnętrznych parametrów do tablicy
   Friend_name[0] = Friend_A;
   Friend_name[1] = Friend_B;
   Friend_name[2] = Friend_C;
   Friend_name[3] = Friend_D;
   Friend_name[4] = Friend_E;
  }

Osobiście zalecam stosowanie input. Jeśli w programie spodziewana jest modyfikacja wartości zewnętrznego parametru, to należy utworzyć zmienną globalną, skopiować do niej wartość i dalej pracować z tą nową zmienną (kod 6).

Kod 6
#property strict
#property script_show_inputs

input int age = 25;  // Mój wiek
int age_value;

//---
void OnStart()
  {
   age_value = age;  // kopiowanie wartości z age do age_value
   age_value++;      // dodanie 1 do zmiennej age_value

   Print("Za rok będę miał " , age_value , " lat.");
  }