lunedì 29 novembre 2010

Aprire un solo ordine per candela: funzione isLastOrderCandle

A seconda del trading system che si intende sviluppare il metodo di gestione delle uscite da un trade può essere differente:

  • chiusura dell'ordine per raggiungimento di take profit o stop loss; 
  • chiusura dell'ordine in seguito a determinati eventi, ad esempio l'incorcio di due medie mobili o altre condizioni.

Nel secondo caso in particolare si possono verificare dei casi per cui il segnale di ingresso è ancora valido e l'ordine viene quindi chiuso ripetutamente ogni volta che se ne apre uno nuovo.

A seconda della strategia adottata una possibile soluzione può essere quella di non aprire nuovi ordini su di una candela se esiste già un ordine chiuso nella stessa barra.

A questo fine si rivelano molto utili due funzioni di metatrader:

  • OrdersHistoryTotal: restituisce il numero di ordini già chiusi presenti all'interno del tab History di metatrader;
  • iBarShift: restituisce il numero della candela più vicina all'orario che viene passato come parametro (nel nostro caso utilizzeremo la funzione OrderOpenTime dopo aver selezionato l'ordine che ci interessa).

bool isLastOrderCandle(){
//TRUE  è già stato aperto un ordine su questa candela
//FALSE non sono stati aperti ordini su questa candela

   int v_LastOrderHistory = OrdersHistoryTotal() - 1;

   if (OrderSelect(v_LastOrderHistory, SELECT_BY_POS, MODE_HISTORY) && (OrderMagicNumber() == e_MagicID))
      if (iBarShift(NULL, 0, OrderOpenTime(), true) == 0)
         return(True);
 
   return(False);
}

Come potete osservare il controllo si basa esclusivamente sul fatto che la candela restituita da iBarShift sia la numero 0. Lo zero, in questo caso, significa che sulla barra attualmente in formazione è già stato effettuato un trade.

E' possibile integrare questa funzione all'interno dello start  dell'expert advisor nell'area dedicata ai controlli per l'apertura di un nuovo ordine oppure subito prima di questa in modo da terminare l'esecuzione dello start, di seguito un possibile esempio:

start(){
   ....
   //gestione ordini aperti
   ...
   if (isLastOrderCandle)
      return(0);
   ...
   //apertura nuovi ordini
   ...
}

Ovviamente esistono modi differenti per fare la stessa cosa, voi quale preferite?
 

13 commenti:

Ale L ha detto...

Ciao Carlo, ho cominciato a fare qualche semplice EA da poco tempo e cercavo proprio una funzione come questa. Però copiando la funzione nel mio programma mi restituisce una serie di errori. La serie di istruzioni

bool isLastOrderCandle(){
...
return (false);

va inserita prima o dopo lo start?

La condizione per la gestione degli ordini aperti:
if (isLastOrderCandle)
return(0);
è corretta? non dovrebbe essere:

if (isLastOrderCandle == true)
return(0);

??? Scusa per l'ignoranza ma come avrai capito sono un novello :(

carlo10 ha detto...

ciao,

la funzione va inserita fuori dallo start, per intenderci dopo l'ultima chiusa graffa.

bool isLastOrderCandle(){
...
return (false);

Se hai altre domande sono a disposizione!

Ti confermo invece che la chiamata alla funzione per la gestione degli ordini aperti è corretta ed è equivalente a quella con la condizione esplicita con l'aggiunta dell' "== true".

In realtà ci la funzione va richiamata anche con le parentesi, nell'esempio sopra mi pare di averle omesse perchè avevo salvato il risultato su di una variabile. Il codice corretto dovrebbe essere questo:

if (isLastOrderCandle())
return(0);

Ale L ha detto...

Ok pare proprio che adesso funzioni! grazie mille Carlo! non ho capito però a cosa serve l'istruzione:

OrderMagicNumber() == e_MagicID

Poichè mi restituiva un errore ho dichiarato una variabile extern int all'inizio del programma a cui gli ho assegnato un numero a caso... è corretto?

Ti ringrazio per la disponibilità

carlo10 ha detto...

E' corretto. Lo stesso numero deve essere utilizzato anche quando apri un ordine, è il parametro magic number. Qui puoi trovare un articolo in cui ne parlo più dettagliatamente:

http://metatrader-forex-trading.blogspot.com/2010/11/come-usare-il-magic-number-negli-expert.html

Flavio ha detto...

ciao a tutti e grazie per i vostri consigli ho provato a insrire questa funzione ma non funzione mi restituisce

'isLastOrderCandle' - function is not defined
dove sbaglio
grazie
sto cercando di creare un ea su dlle mie idee chi puo aiutami ovvio pago il disturbo
grazie

carlo10 ha detto...

Ciao Flavio,

se posso ti aiuto volentieri qui nel blog.

Quel messaggio indica, in fase di compilazione, che non riesce a trovare una funzione che hai richiamato all'interno del codice.

Dovresti assiucurarti di aver inserito nel programma questo blocco di codice, inseriscilo dopo l'ultima parentesi chiusa graffa dello start:

bool isLastOrderCandle(){
//TRUE è già stato aperto un ordine su questa candela
//FALSE non sono stati aperti ordini su questa candela

int v_LastOrderHistory = OrdersHistoryTotal() - 1;

if (OrderSelect(v_LastOrderHistory, SELECT_BY_POS, MODE_HISTORY) && (OrderMagicNumber() == e_MagicID))
if (iBarShift(NULL, 0, OrderOpenTime(), true) == 0)
return(True);

return(False);
}

Poi prova a ricompilare.

Fammi sapere, se non risolvi il problema in caso carica il file su di un hosting gratuito tipo megaupload e posta qui il link.

Carlo

Ale L ha detto...

Ogni tanto nella mia testa mi vengono in mente delle idee che provo a tradurre in mql. In merito a questo argomento (aprire un solo ordine per candela) mi sono chiesto: e se invece volessi aprire un solo ordine ma di un solo tipo (BUY o SELL)?

Mi spiego meglio: vorrei che sulla stessa candela sia consentito di aprire un secondo ordine ma solo se si tratta del tipo opposto a quello che già è stato aperto.

Ad esempio: se viene aperto un ordine BUY su una candela voglio che sia impedita l'apertura di un secondo ordine BUY, ma che invece sia consentita l'apertura di un ordine SELL.

Cosa ne dite? Si può fare?

carlo10 ha detto...

Naturalmente si può fare, è necessario però rivistare la funzione.

Mi viene in mente questo:
- passiamo alla funzione l'ordine che si intende aprire (OP_BUY o OP_SELL)
- aggiungiamo nell'if all'interno della funzione questa condizione: OrderType( ) == OP_SELL?

In partica se voglio aprire uno short e non ci sono short aperti la condizione non sarà verificata e la funzione restituirà come risultato false.

In pratica

Ale L ha detto...

Carlo

ma in questo modo devo sapere a priori se voglio aprire uno short o un long per impostare la condizione nella funzione, giusto?

Supponiamo invece di non sapere se si aprirà un ordine buy o un ordine sell. In base a quello che si apre, immagino che occorra creare una variabile alla quale assegnare OP_BUY o OP_SELL a seconda dell'ordine che viene aperto.

Mi è sembrato di vedere qualcosa che potrebbe fare al caso nostro nel tuo "Alternate Buy and Sell" EA, la variabile e_FirstOperationType ad esempio?

Ale L ha detto...

Ho provato a fare la seguente modifica alla funzione isLastOrderCandle:
_________________________________________________
bool isLastOrderCandle()
{
int v_LastOrderHistory = OrdersHistoryTotal() - 1;

if (OrderSelect(v_LastOrderHistory, SELECT_BY_POS, MODE_HISTORY) && (OrderMagicNumber() == e_MagicID) && (OrderType() == e_FirstOperationType))
if (iBarShift(NULL, 0, OrderOpenTime(), true) == 0)
return(True);

return(False);
}
_______________________________________________

e cioè ho aggiunto una condizione in AND in più, vale a dire che il tipo di ordine sia quello della variabile e_FirstOperationType, alla quale assegno OP_BUY se si apre una posizione long, e OP_SELL se si apre una short:
______________________________________________
int total = OrdersTotal();
if(total < 1)
{

// Apro una posizione BUY?

if ...
{
ticket=OrderSend(Symbol(),OP_BUY,lots,Ask,3,middleB,High[1]+takeprofit*Point,"Compro",e_MagicID,0,Green);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
e_FirstOperationType = OP_BUY;
Print("Aperto Ordine Buy: ",OrderOpenPrice());
}
else Print("Errore nell'apertura dell'ordine Buy: ", GetLastError());
return(0);
}

// Apro una posizione SELL?

if ....
{
ticket=OrderSend(Symbol(),OP_SELL,lots,Bid,3,middleS,Low[1]-takeprofit*Point,"Vendo",e_MagicID,0,Red);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
e_FirstOperationType = OP_SELL;
Print("Aperto Ordine Sell: ",OrderOpenPrice());
}
else Print("Errore nell'apertura dell'ordine Sell: ", GetLastError());
return(0);
}

}
return(0);

}
__________________________________________
Il controllo al solito lo effettuo prima dell'apertura ordini:
______________________________________
int start()
{

...


//controllo ordini aperti sulla candela

if (isLastOrderCandle())
{
Print("c'è già un ordine di quel tipo su questa candela");
return(0);
}

...
_____________________________________

Facendo il backtest ho constatato però che non funziona, cioè se viene aperto un ordine su quella candela, non viene aperto nessun altro ordine, nemmeno di tipo opposto...cioè la funzione isLastOrderCAndle è come se funzionasse come la conosciamo dall'inizio...

carlo10 ha detto...

Io manterrei la logica che ho indicato nel commento precedente.

E' vero che non sai se aprirai una posizione long o short ma puoi sempre spostare e sdoppiare all'interno dello start la chiamata a isLastOrderCandle, esempio:

//Devo aprire un long?
if (condizione1 and condizione 2 and isLastOrderCandle(OP_BUY))

//Devo aprire uno short?
if (condizione1 and condizione 2 and isLastOrderCandle(OP_SELL))

Ale L ha detto...

Perfetto! seguendo le tue indicazioni funziona!
Grazie Carlo

Unknown ha detto...

ciao Carlo...ho fatto creare da un programmatore un EA che apre 2 ordini pendenti una volta al giorno al verificarsi di determinate condizioni...
nell'EA al raggiungimento del take l?ordine opposto viene cancellato
vorrei modificare L'EA per far si che al raggiungimento dello stop invece L'ea mi ripiazza gli stessi identici ordini ordini....
si può fare?

Posta un commento