Początki w programowaniu...

O jezykach programowania w platformach i nie tylko.
padmocho
Bywalec
Bywalec
Posty: 9
Rejestracja: 20 cze 2011, 13:49

Początki w programowaniu...

Nieprzeczytany post autor: padmocho »

Witam,

Dopiero zaczynam przygodę z MetaTrade i MQL-em więc o ile można z góry proszę o wyrozumiałość.

Chciałem napisać jaknajprostrzy program EA który by dokonywał otwarcia zlecenia przy przecięciu się dwóch linii. Do tego celu wykorzystałem poniższy kod:

Kod: Zaznacz cały

extern double    Lots=0.1;
extern double    TakeProfit=350.0;

int Crossed (double line1 , double line2)
{
//static means that variables hold values between repeated calls
static int last_direction = 0;
static int current_dirction = 0;

if (line1>line2) current_dirction = 1; //up
if (line1<line2) current_dirction = 2; //down

if(current_dirction != last_direction) //changed
   {
   last_direction = current_dirction;
   return (last_direction);
   }
   else
   {
   return (0);
   }
}
// --->>> Jak dla mnie to ta funkcja przy pierwszym uruchomieniu ZAWSZE otrzyma wartość 1 lub 2 (chyba że akurat obie linie zaczynają się od tego samego miejsca !!!


int start()
  {
//----
int cnt,ticket,total;
double lineEMA2,lineEMA;

total = OrdersTotal();

lineEMA = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,0);
lineEMA2 = iMA(NULL,0,12,0,MODE_EMA,PRICE_CLOSE,0);

int isCrossed = Crossed (lineEMA,lineEMA2);

if(total < 1)
{
   if(isCrossed == 1)
   {
      ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,0,0,Ask+TakeProfit*Point,"My EA - KUPNO",12345,0,Green);
      // the above should give us the ticket number but if fails it will be eg. -1
      if(ticket>0)
      {
         if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)==true)
         Print("BUY order opened : ",OrderOpenPrice());
      }
      else Print("Error opening BUY order : ",GetLastError());
      return(0);
   }
   if(isCrossed == 2)
   {
      ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"My EA - SELL",12345,0,Red);
      if(ticket>0)
      {
         if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
         Print("SELL order opened : ",OrderOpenPrice());
      }
      else Print("Error opening SELL order : ",GetLastError());
      return(0);
   }
// the following exit when the lines have not crossed yet!
return(0);
}
for(cnt=0;cnt<total;cnt++)
{
   OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
   if(OrderType()<=OP_SELL && OrderSymbol()==Symbol())
   {
      if(OrderType()==OP_BUY) // long position is opened
      {
      // should it be closed?
         if(isCrossed == 2)
         {
            OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet);
            // close position
            return(0); // exit
         }
      // check for trailing stop
//      if(TrailingStop>0)
//      {
//         if(Bid-OrderOpenPrice()>Point*TrailingStop)
//         {
//            if(OrderStopLoss()<Bid-Point*TrailingStop)
//            {
//               OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
//               return(0);
//            }
//         }
//      }
   }
   else // go to short position
   {
   // should it be closed?
      if(isCrossed == 1)
      {
         OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet);
         // close position
         return(0); // exit
      }
   // check for trailing stop
//   if(TrailingStop>0)
//   {
//      if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
//      {
//         if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
//         {
//            OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
//            return(0);
//         }
//      }
//   }
}
}
}
return(0);
}

Po uruchomieniu, niby wszystko działa ale jak patrzę na wykres to miejsca w których otwierane są transakcje wcale nie pokrywają się z miejscem przecięcia dwóch linii (w tym wypadku EMA12 i EMA8).

Czy to ja źlę interpretuję wynik czy jakoś inaczej jest on rysowany w stosunku do kodu? A może są jeszcze jakieś inne warunki o które trzeba byłoby zadbać żeby wykres pokazywał to co program ma faktycznie robić?


Dodatkowo - funkcja Crossed() wydaje mi się być dziwna o tyle że przy pierwszym uruchomieniu zawsze będzie generowała 1 lub 2 a więc otwierana będzie pozycja... co nie jest prawidłowe!


Z góry dziękuję za wszelką pomoc!
Paweł.
[/img]

Awatar użytkownika
thisredone
Stały bywalec
Stały bywalec
Posty: 72
Rejestracja: 05 sie 2010, 17:07

Nieprzeczytany post autor: thisredone »

Pobierasz wartość iMA() na zerowej świeczce co oznacza, że zależnie od tego, który akurat jest tick ta wartość może być inna czyli ta końcówka wskaźnika może się nieco zmieniać przez co generować złe sygnały bo, np. przez chwilę się przetną ale na końcu świeczki nie będzie tego widać.

Przecięcie się tych linii możesz sprawdzić przez pobieranie wartości z dwóch poprzednich świeczek. Czyli, np.

Kod: Zaznacz cały

int Crossed(double _11, double _12, double _21, double _22)
{
   if(_12<_22 && _11<_21) return(1); //przeciecie 1
   if(_12>_22 && _11>_21) return(2); //przeciecie 2
   return(0); //brak przeciecia
}

int start()
{
l1_1 = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,1); 
l2_1= iMA(NULL,0,12,0,MODE_EMA,PRICE_CLOSE,1);
l1_2 = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,2); 
l2_2 = iMA(NULL,0,12,0,MODE_EMA,PRICE_CLOSE,2);

int isCrossed = Crossed(l1_1,l1_2,l2_1,l2_2);
}

padmocho
Bywalec
Bywalec
Posty: 9
Rejestracja: 20 cze 2011, 13:49

Nieprzeczytany post autor: padmocho »

Ach rozumiem!

Czyli że jeśli mam ustawione akurat np. M1 to podczas tej minuty linie mogą się ileś tam razy przeciąć za kolejnymi tickami ale jak już przejdziemy do następnej świeczki to może się okazać że za ostatnim tickiem linie już się nie przecinają... chyba wszystko jasne.
Dzięki za przykład - zobaczę jak mi to będzie szło...

A co można zrobić z tym problemem że pierwsze uruchomienie funkcji Crossed od razu daje 1 albo 2 (czyli że od razu jest otwierana jakaś pozycja)?

Pozdrawiam,
Paweł.

PS. Gdzie jeszcze mogę znaleźć jakieś materiały szkoleniowe z MQL-a? W Internecie udało mi się znaleźć tylko jeden dokument i to jeszcze kiepskiej jakości... :(

Awatar użytkownika
thisredone
Stały bywalec
Stały bywalec
Posty: 72
Rejestracja: 05 sie 2010, 17:07

Nieprzeczytany post autor: thisredone »

padmocho pisze: A co można zrobić z tym problemem że pierwsze uruchomienie funkcji Crossed od razu daje 1 albo 2 (czyli że od razu jest otwierana jakaś pozycja)?
możesz przy warunku, który zwraca wynik (przecięcie) dopisać kolejny warunek, że jeżeli wartość zmiennej last_direction==0 to zwracasz '0' i uaktualniasz last_direction lub w funkcji int init() obliczyć wartość last_direction (to oczywiście wymaga zmian w kodzie, np. przeniesienia zmiennych static do zmiennych globalnych).

co do materiałów pomocniczych to jedyne co mi przychodzi do głowy to http://docs.mql4.com
Jest tam opis wszystkich funkcji, a ty po prostu z czasem musisz nauczyć się ich używać.

padmocho
Bywalec
Bywalec
Posty: 9
Rejestracja: 20 cze 2011, 13:49

Nieprzeczytany post autor: padmocho »

Bardzo dziękuję za pomoc!

Żeby pozbyć się problemu z pierwszym przebiegiem dodałem tylko jeden warunek:
if (last_direction == 0) last_direction = current_dirction;
i to załatwiło sprawę.

Natomiast nie wiem jak ustosunkować się do problemu z generowaniem pozycji podczas kształtowania się świeczki...
Chodzi mi o to że:

1. Jeśli zostawię tak jak było tzn. sprawdzane są tylko bieżące sygnały to faktycznie dostaję ich pełno i mogą być (bardzo często są) fałszywe.

2. Jeśli zastosuję Twoją radę (tzn. sprawdzenie poprzedniej świeczki (bar) to w zależności od tego jaki mam okres mogę odfiltrować za dużo... np. przy M15 dostaję jedynie jedną pozycję na 2 dni... a to przecież dopiero jeden wskaźnik który chcę wykorzystać :(

Poza tym którą wartość mam badać?
Przykładowo - chcę wygenerować sygnał po przecięciu się lini ceny z EMA:

Kod: Zaznacz cały

int isCrossedEMA = Crossed(iClose(Symbol(),0,0),longEma,iClose(Symbol(),0,1),longEmaPrevious);
czyli:
- sprawdzam czy cena zamknięcia i EMA przecięły się w dwóch kolejnych świeczkach - czy iClose jest sensowną wartością? Czy może powinno być iOpen lub iHigh itd?

Czy są jakieś ogólne standardy w programowaniu dot. sposobu badania się przecięcia dwóch linii (np. ceny i EMA)?

Mam jeszcze jedno pytanie dot. potwierdzenia sygnału (tzn. jeśli cena i EMA się przetną i RSI przetnie 50 to dopiero generuj sygnał) - ale to pewnie w innym wątku dam żeby za bardzo nie mieszać tutaj.

Pozdrawiam,
Paweł.

Awatar użytkownika
thisredone
Stały bywalec
Stały bywalec
Posty: 72
Rejestracja: 05 sie 2010, 17:07

Nieprzeczytany post autor: thisredone »

Nie ma ogólnych standardów, piszesz jak chcesz ;)

zauważ jednak, że ta funkcja, którą ci napisałem ma inaczej poukładane argumenty czyli zamiast twojego

Kod: Zaznacz cały

Crossed(Close[0],longEma,Close[1],longEmaPrevious);
powinno być

Kod: Zaznacz cały

Crossed(Close[0],Close[1],longEma,longEmaPrevious);
Co do tego RSI to zwyczajnie dodajesz kolejny warunek i zmienną. Możesz to zrobić tak samo w odrębnej funkcji jak to masz z przecięciem.

Kod: Zaznacz cały

int isCrossed = Crossed (lineEMA,lineEMA2);
int rsiSignal = rsiCheck();

if(total < 1) 
{ 
    if(isCrossed == 1 && rsiSignal ==1)
    (...)
    else if(isCrossed == 2 && && rsiSignal==2)
gdzie rsiCheck() to funkcja, w której sprawdzasz warunek dot. RSI.

padmocho
Bywalec
Bywalec
Posty: 9
Rejestracja: 20 cze 2011, 13:49

Nieprzeczytany post autor: padmocho »

Jeśli chodzi o Twoją funkcję to mam w tej chwili tak:

Kod: Zaznacz cały

int Crossed (double line1, double line2,double line1_previous_bar, double line2_previous_bar)
{
//static means that variables hold values between repeated calls
static int last_direction = 0;
static int current_dirction = 0;

//at first run current_dirction will become 1 or 2 but not 0!
if (line1>line2 && line1_previous_bar>line2_previous_bar) current_dirction = 1; //line1 is above
if (line1<line2 && line1_previous_bar<line2_previous_bar) current_dirction = 2; //line1 is below
...
więc

Kod: Zaznacz cały

int isCrossedEMA = Crossed(iClose(Symbol(),0,0),longEma,iClose(Symbol(),0,1),longEmaPrevious);
wydaje mi się być prawidłowe... ale mogę się oczywiście mylić - daj znać jeśli powyższe jest błędne!

Co do RSI to poniższy kod będzie prawdziwy tylko jeśli oba wskaźniki przetną się w tym samym ticku prawda? A takiej sytuacji chyba raczej nie należy oczekiwać?

Innymi słowy myślę że lepiej byłoby żeby najpierw sprawdzany był jeden wskaźnik (np. EMA) a potem drugi (jako jego potwierdzenie). Mój problem to jak usyskać to "potem"?

Awatar użytkownika
thisredone
Stały bywalec
Stały bywalec
Posty: 72
Rejestracja: 05 sie 2010, 17:07

Nieprzeczytany post autor: thisredone »

W funkcji int Crossed() naprawdę polecam zrezygnować z tych statycznych zmiennych bo nie są potrzebne. Funkcja, którą ci zapisałem jest kompletna i nie wymaga dodatkowych modyfikacji.

Co do tego 'potem' to zmienia to twój system.

Oczywiście mógłbyś zrobić coś takiego:

Kod: Zaznacz cały

   l1_1 = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,1); 
   l2_1 = iMA(NULL,0,12,0,MODE_EMA,PRICE_CLOSE,1); 
   l1_2 = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,2); 
   l2_2 = iMA(NULL,0,12,0,MODE_EMA,PRICE_CLOSE,2); 

   int isCrossed = Crossed(l1_1,l1_2,l2_1,l2_2); 
 
   if(isCrossed == 1) sygnalEMA = 1;
   else if(isCrossed == 2) sygnalEMA = 2;
 
   if(sygnalEMA == 1 && sygnalRSI == 1)
   {
      (...)
   }
   else if(sygnalEMA == 2 && sygnalRSI == 2)
   {
      (...)
   }
ale po co?
Jeżeli interesuje cię opcja, w której było przecięcie dwóch linii EMA w przeszłości i wygeneruje się sygnał RSI to zamiast sprawdzać przecięcia EMA wystarczy sprawdzić, która jest nad którą.

Obrazek
czyli w momencie wygenerowania się sygnału RSI sprawdzasz po prostu czy odpowiednia EMA jest na drugą.

ODPOWIEDZ