Funkcje transakcji:   OrderSend()

Jest to podstawowa funkcja stosowana do zawierania transakcji handlowych. Funkcja int OrderSend() zwraca unikalny numer (ticket) pozycji/zlecenia jeśli operacja się powiodła, inaczej zwróci -1. Więcej informacji można znaleźć w specyfikacji MQL4.

OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
string symbol - nazwa instrumentu finansowego (symbolu).
int cmd - typ operacji handlowej. Może być jedną z wartości typów operacji handlowych.
double volume - ilość lotów (wolumen) transakcji.
double price - cena otwarcia.
int slippage - poślizg cenowy, tj. dopuszczalna różnica w punktach między zleconą ceną otwarcia pozycji a rzeczywistą ceną rynkową.
double stoploss - poziom ceny, po osiągnięciu którego następuję zamknięcie pozycji ze stratą.
double takeprofit - poziom ceny, po osiągnięciu którego następuję zamknięcie pozycji z zyskiem.
string comment - komentarz do zlecenia. Ostatnia część komentarza może być zmieniona przez serwer handlowy. Wartość domyślna = NULL , tj. brak komentarza.
int magic - unikalny identyfikator (magic number). Wartość domyślna = 0.
datetime expiration - czas wygaśnięcia oczekującego zlecenia zgodnie z czasem serwera. Wartość domyślna = 0, tj. nigdy nie wygasa.
color arrow_color - kolor strzałki na wykresie. Wartość domyślna = clrNONE , tj. strzałka na wykresie nie jest wyświetlana.

string symbol - nazwa instrumentu finansowego (symbolu).

int cmd - typ operacji handlowej. Może być jedną z wartości typów operacji handlowych.

double volume - ilość lotów (wolumen) transakcji.

double price - cena otwarcia.

int slippage - poślizg cenowy, tj. dopuszczalna różnica w punktach między zleconą ceną otwarcia pozycji a rzeczywistą ceną rynkową.

double stoploss - poziom ceny, po osiągnięciu którego następuję zamknięcie pozycji ze stratą.

double takeprofit - poziom ceny, po osiągnięciu którego następuję zamknięcie pozycji z zyskiem.

string comment - komentarz do zlecenia. Ostatnia część komentarza może być zmieniona przez serwer handlowy. Wartość domyślna = NULL , tj. brak komentarza.

int magic - unikalny identyfikator (magic number). Wartość domyślna = 0.

datetime expiration - czas wygaśnięcia oczekującego zlecenia zgodnie z czasem serwera. Wartość domyślna = 0, tj. nigdy nie wygasa.

color arrow_color - kolor strzałki na wykresie. Wartość domyślna = clrNONE , tj. strzałka na wykresie nie jest wyświetlana.


W MQL4 operacje handlowe (cmd) można podzielić na 2 grupy:

  • otwarcie pozycji po bieżącej cenie rynkowej (egzekucja natychmiastowa),
  • umieszczenie zlecenia oczekującego.

Do 1-ej grupy zaliczają się operacje :

  • OP_BUY     - kupić po bieżącej cenie rynkowej Ask ,
  • OP_SELL  - sprzedać po bieżącej cenie rynkowej Bid .
  • OP_BUY - kupić po bieżącej cenie rynkowej Ask ,
  • OP_SELL - sprzedać po bieżącej cenie rynkowej Bid .

Do 2-ej grupy zaliczają się operacje :

  • OP_BUYLIMIT    - umieścić zlecenie kupna poniżej bieżącej ceny rynkowej,
  • OP_SELLLIMIT  - umieścić zlecenie sprzedaży powyżej bieżącej ceny rynkowej,
  • OP_BUYSTOP       - umieścić zlecenie kupna powyżej bieżącej ceny rynkowej
  • OP_SELLSTOP    - umieścić zlecenie sprzedaży poniżej bieżącej ceny rynkowej.
  • OP_BUYLIMIT - umieścić zlecenie kupna poniżej bieżącej ceny rynkowej,
  • OP_SELLLIMIT - umieścić zlecenie sprzedaży powyżej bieżącej ceny rynkowej,
  • OP_BUYSTOP - umieścić zlecenie kupna powyżej bieżącej ceny rynkowej
  • OP_SELLSTOP - umieścić zlecenie sprzedaży poniżej bieżącej ceny rynkowej.

Przykład 1

Skrypt na otwarcie pozycji kupna.

#property strict
void OnStart()
  {
//--- dane dla otwarcia pozycji
   string   symbol      = _Symbol;       // bieżący instrument finansowy
   int      cmd         = OP_BUY;        // typ operacji, kupno
   double   volume      = 0.01;          // wolumen transakcji
   int      slippage    = 50;            // poślizg cenowy w punktach
   int      stops       = 300;           // ilość punktów dla stoploss i takeprofit
   string   comment     = "My comment";  // komentarz
   int      magic       = 555;           // unikalny identyfikator (magic number)
   datetime expiration  = 0;             // czas wygaśnięcia
   color    arrow_color = clrBlue;       // kolor zamykającej strzałki

//--- odświeżyć notowania
   RefreshRates();
//--- obliczyć ceny stoploss i takeprofit
   double LevelStopLoss   = Ask - (stops * _Point);
   double LevelTakeProfit = Ask + (stops * _Point);
//--- znormalizować ceny
   LevelStopLoss   = NormalizeDouble(LevelStopLoss, _Digits);
   LevelTakeProfit = NormalizeDouble(LevelTakeProfit, _Digits);

//--- otworzyć pozycję
   if(OrderSend(symbol, cmd, volume, Ask, slippage, LevelStopLoss, LevelTakeProfit,
                comment, magic, expiration, arrow_color) < 0)
      Print("Nie udało się otworzyć pozycję kupna. Błąd = ",GetLastError());
   else
      Print("Otwarto pozycję kupna.");
  }

Rys. 1. Przykład stosowania funkcji OrderSend().


Przykład 2

Skrypt na otwarcie pozycji sprzedaży po bieżącej cenie rynkowej: GBPUSD, wolumenem 0.3, stoploss 300 punktów a takeprofit 500 od ceny otwarcia pozycji, magic number 777.

#property strict
void OnStart()
  {
//--- dane dla otwarcia pozycji
   string symbol = "GBPUSD";  // instrument finansowy
   int    SL     = 300;       // ilość punktów dla stoploss
   int    TP     = 500;       // ilość punktów dla takeprofit

//--- znaleźć bieżącą cenę rynkową na sprzedaż dla GBPUSD
   double SymbolBid = MarketInfo(symbol, MODE_BID);

//--- obliczyć i znormalizować ceny stoploss i takeprofit
   double LevelStopLoss   = NormalizeDouble(SymbolBid + (SL * _Point), _Digits);
   double LevelTakeProfit = NormalizeDouble(SymbolBid - (TP * _Point), _Digits);

//--- otworzyć pozycję na GBPUSD, sprzedaż, wolumen = 0.3, bieżąca cena rynkowa dla GBPUSD,
//--- poślizg cenowy = 50 pkt, magic number = 777
   if(OrderSend(symbol, OP_SELL, 0.3, SymbolBid, 50, LevelStopLoss, LevelTakeProfit, NULL, 777) < 0)
      Print("Nie udało się otworzyć pozycję sprzedaży dla ",symbol,". Błąd = ",GetLastError());
   else
      Print("Otwarto pozycję sprzedaży dla ",symbol);
  }

Rys. 2. Przykład stosowania funkcji OrderSend().


W celu otwarcia pozycji kupna OP_BUY lub sprzedaży OP_SELL, należy stosować tylko bieżące ceny rynkowe Ask (kupna) lub Bid (sprzedaży) (przykład 1). Jeśli operacja jest realizowana dla innego instrumentu finansowego niż dla wykresu notowań, gdzie program MQL4 został uruchomiony, należy zastosować funkcję MarketInfo() z identyfikatorem MODE_ASK lub MODE_BID w celu uzyskania Ask lub Bid właściwego instrumentu finansowego (przykład 2).

Jeśli podjąć próbę otwarcia pozycji po cenie, której nie ma na rynku lub cena nie jest znormalizowana, zostanie wygenerowany błąd 129 (ERR_INVALID_PRICE), tj. nieprawidłowa cena. Jeśli żądana cena jest nie aktualna, to niezależnie od wartości poślizgu cenowego slippage zostanie wygenerowany błąd 138 (ERR_REQUOTE), tj. przekwotowywanie. Jeśli cena nie jest aktualna, ale jest obecna w strumieniu cenowym, to pozycja jest otwierana po bieżącej cenie rynkowej jeśli znajduje się ona w zakresie poślizgu cenowego.

Ceny StopLoss i Takeprofit nie mogą znajdować się zbyt blisko ceny otwarcia pozycji oraz ceny otwarcia oczekującego zlecenia. Minimalną odległość do stop-ów w punktach można uzyskać za pomocą MarketInfo(symbol, MODE_STOPLEVEL). W przypadku błędnych oraz nieznormalizowanych stop-ów zostanie wygenerowany błąd 130 (ERR_INVALID_STOPS), tj. nieprawidłowy poziom stop. Jeśli MarketInfo(symbol, MODE_STOPLEVEL) zwróci 0 to znaczy, że albo brak jest ograniczeń na minimalną odlęgłośc dla tych stop-ów, albo serwer handlowy używa zewnętrzne mechanizmy dynamicznej kontroli poziomów, które nie mogą być przekazane terminalowi MetaTrader 4. W drugim przypadku GetLastError() może zwrócić błąd 130, ponieważ poziom MODE_STOPLEVEL jest ruchomy.

Podczas umieszczenia oczekującego zlecenia, jego cena otwarcia nie może znajdować się zbyt blisko bieżącej ceny rynkowej. Minimalną odległość między tymi cenami w punktach można także uzyskać za pomocą MarketInfo(symbol, MODE_STOPLEVEL). W przypadku nieprawidłowej ceny otwarcia oczekującego zlecenia zostanie wygenerowany błąd 130 (ERR_INVALID_STOPS).

Na niektórych serwerach handlowych może być wyłączona możliwość ustawienia czasu wygaśnięcia oczekującego zlecenia. W takich przypadkach, próbując ustawić niezerową wartość w expiration zostanie wygenerowany błąd 147 (ERR_TRADE_EXPIRATION_DENIED).

Niektóre serwery mogą mieć limit na łączną ilość otwartych pozycji i oczekujących zleceń. Jeśli limit zostanie osiągnięty to próba otwarcia nowej pozycji lub oczekującego zlecenia wygeneruje błąd 148 (ERR_TRADE_TOO_MANY_ORDERS), tj. liczba zleceń osiągnęła ograniczenie ustawione przez brokera. W celu sprawdzenia limitu należy zastosować zapis AccountInfoInteger(ACCOUNT_LIMIT_ORDERS) .

Niektórzy brokerzy mogą nie akceptować ustawiania StopLoss-ów i TakeProfit-ów w momencie otwarcia pozycji lub oczekującego zlecenia. W tym przypadku w OrderSend() na miejscu stoploss oraz takeprofit należy wpisać 0, a następnie po akceptacji przez serwer tej pozycji/zlecenia za pomocą OrderModify() można zmodyfikować stop-y.


Przykład 3

Skrypt na umieszczenie oczekującego zlecenia kupna OP_BUYLIMIT poniżej ceny rynkowej na 200 punktów, ze stoploss 300 i takeprofit 500 punktów dla tego instrumentu finansowego, gdzie skrypt zostanie uruchomiony.

#property strict
void OnStart()
  {
//--- dane dla umieszczenia oczekującego zlecenia
   int OP = 200;  // ilość punktów dla umieszczenia zlecenia od ceny rynkowej
   int SL = 300;  // ilość punktów dla stoploss
   int TP = 500;  // ilość punktów dla takeprofit

//===================== kontrola błędów =====================
//--- znaleźć minimalną odległość dla stop-ów
   int StopLevelMin = (int)MarketInfo(_Symbol, MODE_STOPLEVEL);

//--- sprawdzić czy cena otwarcia zlecenia nie jest zbyt blisko bieżącej ceny rynkowej
   if(OP <= StopLevelMin)
     {
      Print("Róźnica w ",OP," punktów od ceny rynkowej to zbyt mało dla oczekującego zlecenia.",
            " Dopuszczalna ilość punktów = ",StopLevelMin);
      return;
     }
//--- sprawdzić czy StopLoss nie jest zbyt blisko ceny otwarcia zlecenia
   if(SL <= StopLevelMin)
     {
      Print("Róźnica w ",SL," punktów to zbyt mało dla StopLoss. Dopuszczalna ilość punktów = ",StopLevelMin);
      return;
     }
//--- sprawdzić czy Takeprofit nie jest zbyt blisko ceny otwarcia zlecenia
   if(TP <= StopLevelMin)
     {
      Print("Róźnica w ",TP," punktów to zbyt mało dla TakeProfit. Dopuszczalna ilość punktów = ",StopLevelMin);
      return;
     }
//--- sprawdzić czy osiągnięto limit pozycji i zleceń
   int CurrentOrders = OrdersTotal();                                 // bieżąca ilość pozycji i zleceń
   int LimitOrders   = (int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); // limit dopuszczalnej ilości pozycji i zleceń
   if(CurrentOrders == LimitOrders)
     {
      Print("Osiągnięto limit dopuszczalnej ilości pozycji i zleceń. Błąd = ",GetLastError(),
            ". Limit = ",StopLevelMin);
      return;
     }

//========= umieścić oczekujące zlecenie na kupno OP_BUYLIMIT ========= 
//--- odświeżyć notowania
   RefreshRates();
//--- obliczyć i znormalizować ceny otwarcia zlecenia LevelOpenPrice,
//--- stoploss LevelStopLoss i takeprofit LevelTakeProfit
   double LevelOpenPrice  = NormalizeDouble(Ask - (OP * _Point), _Digits);
   double LevelStopLoss   = NormalizeDouble(LevelOpenPrice - (SL * _Point), _Digits);
   double LevelTakeProfit = NormalizeDouble(LevelOpenPrice + (TP * _Point), _Digits);

//--- umieścić oczekujące zlecenie dla bieżącego instrumentu finansowego
//--- wolumen = 0.3
   if(OrderSend(_Symbol, OP_BUYLIMIT, 0.3, LevelOpenPrice, 0, LevelStopLoss, LevelTakeProfit) < 0)
      Print("Nie udało się umieścić zlecenie OP_BUYLIMIT dla ",_Symbol,". Błąd = ",GetLastError());
   else
      Print("Udało się umieścić zlecenie OP_BUYLIMIT dla ",_Symbol);
  }