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:
Do 1-ej grupy zaliczają się operacje :
Do 2-ej grupy zaliczają się operacje :
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().
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.
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); }