Sei sulla pagina 1di 80

Lavorare con le funzioni

if (argAdjustPrice <= UpperStopLevel)


{doppie AdjustedPrice = UpperStopLevel + (argAddPips * PipPoint (argSymbol)); }

altro AdjustedPrice = argAdjustPrice;

ritorno (AdjustedPrice); }

L'argomento argAdjustPrice è il prezzo che verificheremo e regolare se è valido. Abbiamo aggiunto un nuovo parametro opzionale, argAddPips.
Questo aggiungerà il numero specificato di pips al livello di prezzo di arresto quando si regola un prezzo valido.

Come prima, si calcola il livello di arresto, rispetto sia al prezzo Ask o argOpenPrice
parametro. Se la argAdjustPrice parametro è all'interno del livello di arresto ( vale a dire non valido), il prezzo verrà regolato in modo che sia al di

fuori del livello di arresto per il numero di semi specificati da argAddPips.

Se il prezzo indicato dal argAdjustPrice è valida, che il prezzo sarà passato di nuovo alla funzione chiamante. In ogni caso, il valore di
ritorno è quello che si vuole utilizzare per il take profit, arrestare la perdita o il prezzo ordine pendente. Useremo queste funzioni in questo
libro per verificare i livelli di arresto e regolare di conseguenza i nostri prezzi. Le funzioni per calcolare e verificare il livello di battuta
inferiore si trovano nell'Appendice D.

Aggiungere Stop Loss e Take Profit

In linea con la nostra idea di tenere le funzioni incentrati su compiti semplici e discreti, abbiamo spostato la nostra modifica al fine di
una funzione separata. Questa funzione aggiungere o modificare lo stop loss e prendere profitto sul nell'ordine specificato. Si
suppone lo stop loss e prendere profitto i prezzi sono già stati calcolati e verificati:

bool AddStopProfit (int argTicket, Doppio argStopLoss, Doppio argTakeProfit)


{ if (argStopLoss == 0 && argTakeProfit == 0) return (false);

OrderSelect ( argTicket, SELECT_BY_TICKET); doppio OpenPrice =


OrderOpenPrice ();

while (IsTradeContextBusy ()) del sonno (10);

// Modifica ordine
bool TicketMod = OrderModify ( argTicket, OrderOpenPrice (), argStopLoss, argTakeProfit, 0);

73
E XPERT UN dvisor P ROGRAMMAZIONE

// Gestione degli errori se (TicketMod


== false)
{Int ErrorCode = GetLastError ();

stringa ErrDesc = ErrorDescription (ErrorCode);

stringa ErrAlert = StringConcatenate (" Aggiungere Stop / Utile - Errore", ErrorCode, ":",
ErrDesc); Alert
(ErrAlert);

stringa ErrLog = StringConcatenate ( "Bid:", MarketInfo (OrderSymbol (), MODE_BID),


" Chiedere: ", MarketInfo (OrderSymbol (), MODE_ASK)," Biglietto:", argTicket,
" Fermare: ", argStopLoss," Profitto: ", argTakeProfit);
Print (ErrLog); }

ritorno (TicketMod); }

Controlliamo per vedere se è stato fornito sia uno stop loss o di un prezzo take profit. In caso contrario, ci sarà uscire dalla funzione. In caso

contrario, modificheremo l'ordine utilizzando lo stop loss e take profit che è stato passato alla funzione. La funzione di gestione degli errori viene

eseguito se la modifica ordine non ha avuto successo. Questa funzione funziona su tutti i tipi di ordine.

Utilizzando Includi file

Per mantenere le nostre funzioni organizzate per facilitare l'inserimento nei nostri file di codice sorgente, ci collochiamo le funzioni in un file di inclusione.

Un file di inclusione può essere costituito da dichiarazioni di funzioni, funzioni di importazione ed eventuali variabili globali o esterni che si desidera

includere in un consulente esperto.

Includi file non richiedono sintassi speciale. Dichiarate le funzioni e le variabili nel file di inclusione proprio come si farebbe in qualsiasi file
di codice sorgente. Includere file non dovrebbero avere un init (), start () o deinit ()
funzione. Il file deve avere un. MQH estensione ed essere situato nella cartella \ \ include esperti cartella.

Tutte le funzioni che creiamo in questo libro saranno inseriti in un file di inclusione denominato

IncludeExample.mqh. Il contenuto di questo file sono elencati in Appendice D.

Utilizzo delle librerie

Una libreria è una raccolta compilata di funzioni. Considerando che un file di inclusione è un file di codice sorgente il cui contenuto
viene "incluso" nel file eseguibile, una biblioteca è un eseguibile separato che contiene le funzioni importate. Pertanto è necessario
che sia il consulente esperto eseguibile e l'eseguibile libreria per eseguire il vostro EA.

74
Lavorare con le funzioni

Le biblioteche sono memorizzati nella cartella \ esperti \ librerie cartella. I file di codice sorgente hanno un. mq4

estensione, e gli eseguibili hanno un. ex4 estensione. Le biblioteche non hanno un start (), init () o
deinit () funzione. Per dichiarare un file come una libreria, è necessario inserire il # biblioteca immobili

direttiva del preprocessore all'inizio del file.

Il vantaggio di librerie è che sono compilati, quindi se avete bisogno per distribuire una libreria di funzioni, è possibile farlo senza esporre
la vostra proprietà intellettuale, come si farebbe se si ha distribuito un file di inclusione. È inoltre possibile effettuare correzioni di bug in
una libreria senza dover ricompilare i consulenti esperti - fino a quando non si apportano modifiche alle dichiarazioni di funzione, come
l'aggiunta e la rimozione di argomenti o funzioni.

Ci sono alcuni svantaggi per le biblioteche come bene. Poiché sono già compilati, non è possibile per il compilatore di verificare se i parametri

sono corretti. Non è possibile specificare un valore predefinito per un parametro in una funzione di libreria, il che significa che sarà necessario

specificare un valore per ogni argomento in una chiamata di funzione. Non è possibile utilizzare variabili esterne in una libreria, o creare variabili

ambito globale che il vostro consulente esperto può accedere.

Avrete bisogno di usare il # importare direttiva per importare le funzioni di libreria nel vostro consulente esperto. Se la libreria contiene

numerose funzioni, può essere meglio per creare un file di inclusione con il # importare

dichiarazioni. Questo aumenta il numero di file di cui ha bisogno per lavorare. Se non avete una buona ragione per utilizzare le librerie, si

suggerisce che si bastone con includere i file per la memorizzazione delle funzioni.

È inoltre possibile importare funzioni da DLL di Windows usando # importare direttive. Il WinUser32.mqh
includere file in \ esperti \ include ha numerosi esempi che vengono utilizzati per la Casella dei messaggi()
funzione. (Discuteremo la Casella dei messaggi() funzione nel capitolo 8). Utilizzando funzioni DLL è un uso avanzato, che non
tratteremo qui. Ci sono articoli sul sito web MQL4 sull'uso DLL per coloro che sono interessati.

Un consulente esperto semplice (con le funzioni)

Ecco il nostro codice sorgente consulente esperto, come appare nel file di codice sorgente. Si suppone che le funzioni che abbiamo creato

in questo capitolo sono dichiarati nel file di inclusione IncludeExample.mqh, i contenuti della quale sono contenuti nell'Appendice D.

// preprocessore
# includere <IncludeExample.mqh>

// variabili esterne
extern bool DynamicLotSize = true; extern double
EquityPercent = 2; extern double FixedLotSize = 0,1;

75
E XPERT UN dvisor P ROGRAMMAZIONE

extern double StopLoss = 50; extern double


TakeProfit = 100;

extern int Unità = 5; extern int MagicNumber =


123;

extern int FastMAPeriod = 10; extern int


SlowMAPeriod = 20;

// variabili globali int BuyTicket;


int SellTicket; doppio UsePoint;
int UseSlippage;

// Init funzione int init ()

{UsePoint = PipPoint (Simbolo ());

UseSlippage = GetSlippage (Simbolo (), lo slittamento); }

// Avvia Funzione int start ()

{// media mobile

doppio FastMA = iMA (NULL, 0, FastMAPeriod, 0,0,0,0); doppio SlowMA = iMA


(NULL, 0, SlowMAPeriod, 0,0,0,0);

// Dimensioni Calcolare Lot


Misura di doppia = CalcLotSize (DynamicLotSize, EquityPercent, StopLoss, FixedLotSize); Misura di = VerifyLotSize (Misura di lotto);

// Acquistare Order
if (FastMA> SlowMA && BuyTicket == 0)
{If (SellTicket> 0) int chiuso = CloseSellOrder (Simbolo (), SellTicket, UseSlippage);

SellTicket = 0;

BuyTicket = OpenBuyOrder (Simbolo (), Misura di lotto, UseSlippage, MagicNumber);

if (BuyTicket> 0 && (StopLoss> 0 || TakeProfit> 0))


{OrderSelect (BuyTicket, SELECT_BY_TICKET);

doppio OpenPrice = OrderOpenPrice ();

76
Lavorare con le funzioni

doppia BuyStopLoss = CalcBuyStopLoss (Simbolo (), StopLoss, OpenPrice); if (BuyStopLoss> 0)

{BuyStopLoss = AdjustBelowStopLevel (Simbolo (), BuyStopLoss, 5); }

doppia BuyTakeProfit = CalcBuyTakeProfit (Simbolo (), TakeProfit, OpenPrice); if (BuyTakeProfit> 0)

{BuyTakeProfit = AdjustAboveStopLevel (Simbolo (), BuyTakeProfit, 5); }

AddStopProfit (BuyTicket, BuyStopLoss, BuyTakeProfit); }}

// Sell Order
if (FastMA <SlowMA && SellTicket == 0)
{If (BuyTicket> 0) Chiuso = CloseBuyOrder (Simbolo (), BuyTicket, lo slittamento);

BuyTicket = 0;

SellTicket = OpenSellOrder (Simbolo (), Misura di lotto, UseSlippage, MagicNumber);

if (SellTicket> 0 && (StopLoss> 0 || TakeProfit> 0))


{OrderSelect (SellTicket, SELECT_BY_TICKET);

OpenPrice = OrderOpenPrice ();

doppia SellStopLoss = CalcSellStopLoss (Simbolo (), StopLoss, OpenPrice); if (SellStopLoss> 0)

{SellStopLoss = AdjustAboveStopLevel (Simbolo (), SellStopLoss, 5); }

doppia SellTakeProfit = CalcSellTakeProfit (Simbolo (), TakeProfit, OpenPrice); if (SellTakeProfit> 0)

{SellTakeProfit = AdjustBelowStopLevel (Simbolo (), SellTakeProfit, 5); }

AddStopProfit (SellTicket, SellStopLoss, SellTakeProfit); }}

ritorno (0); }

77
E XPERT UN dvisor P ROGRAMMAZIONE

Iniziamo includendo il file che contiene le nostre funzioni in esso, in questo caso IncludeExample.mqh. Le dichiarazioni delle
variabili e dei contenuti della dentro() funzione sono gli stessi di prima. All'inizio del inizio() la funzione, usiamo CalcLotSize () e VerifyLotSize
() per calcolare e verificare la nostra dimensione del lotto.

Nei nostri blocchi di ordine comprare e vendere, usiamo CloseBuyOrder () e CloseSellOrder () per chiudere l'ordine inverso. I nuovi
ordini sono aperti utilizzando OpenBuyOrder () o OpenSellOrder (). Prima di calcolare lo stop loss e take profit, controlliamo che
l'ordine è stato aperto e che un StopLoss o
Avere un profitto è stato specificato.

Abbiamo il recupero del prezzo dell'ordine di apertura utilizzando OrderSelect () e OrderOpenPrice (). Abbiamo poi calcoliamo il nostro stop loss

utilizzando CalcBuyStopLoss () o CalcSellStopLoss (), e il nostro take profit utilizzando

CalcBuyTakeProfit () o CalcSellTakeProfit ().

Controlliamo per vedere se lo stop loss o prendere profitto è maggiore di 0, e utilizzare le funzioni

AdjustAboveStopLevel () e AdjustBelowStopLevel () per verificare il nostro stop loss e prendere i prezzi di profitto. Infine, passiamo

tali prezzi al AddOrderProfit () funzione, che aggiunge lo stop loss e take profit per l'ordine.

L'EA sopra fa esattamente la stessa cosa come il codice a partire da pagina 51, ma è molto più facile da leggere. Rompendo il codice in

funzioni, abbiamo de-ingombra il nostro codice sorgente e reso la nostra EA più facile da gestire. Noi aggiungeremo qualche funzionalità a

questo consulente esperto prima della fine del libro. È possibile visualizzare il codice completo in Appendice C.

Il lavoro iniziale nella creazione di queste funzioni ci vorrà del tempo, ma vi farà risparmiare tempo nel lungo periodo, come si sarà più facilmente

in grado di realizzare prototipi e idee di trading risultano consulenti esperti che lavorano in un breve lasso di tempo.

78
Lavorare con le funzioni

79
E XPERT UN dvisor P ROGRAMMAZIONE

Capitolo 5
Gestione degli ordini

Hai già stato introdotto al OrderSelect () funzione nel capitolo 2. In questa sezione, useremo la OrderSelect () funzione con gli
operatori ciclo per e mentre, per scorrere la piscina ordine e recuperare le informazioni ordine. Questo metodo viene utilizzato
per chiudere più ordini, aggiungere trailing stop, contare il numero di ordini aperti, e altro ancora.

L'Ordine Loop Il per Operatore

Il per operatore viene utilizzato per il ciclo in un blocco di codice per un numero predeterminato di volte. Si dichiara una variabile intera

da utilizzare come un contatore, e assegnare un valore iniziale. Indichiamo la condizione che, se vera, farà sì che il ciclo per

l'esecuzione. Indichiamo anche un'espressione che per incrementare la variabile contatore.

Ecco un esempio di per ciclo continuo:

for (int contatore = 1; contatore <= 3; contatore ++)


{// Codice da ciclo}

La prima espressione, int contatore = 1, inizializza il nostro contatore variabile con un valore di 1. La seconda espressione, Contatore <=
3, è la condizione che, se vera, eseguirà il codice all'interno delle parentesi. Se false, il ciclo è concluso, e l'esecuzione continua dopo la

parentesi finale (}).

La terza espressione, Contatore ++, significa "incrementare il valore di contatore per uno." L'espressione
Counter-- avrebbe decrementare il valore di uno, e Contatore + 2 sarebbe incrementato di due. Ogni volta che il ciclo viene completata, la

variabile contatore viene incrementato o decrementato. Nella successiva iterazione del ciclo, il secondo argomento, in questo caso Contatore
<= 3, è ri-valutato. Si noti che non v'è alcun punto e virgola dopo la terza espressione.

L'esempio precedente eseguire il ciclo tre volte. Dopo ogni iterazione, il contatore viene incrementato di uno, e dopo la terza
iterazione del ciclo termina.

80
Gestione degli ordini

Il mentre Operatore

Il mentre operatore è un metodo più semplice di loop in MQL. Il per ciclo è meglio se si sa esattamente quante volte si pensa di
esecuzione del ciclo. Se non si è sicuri del numero di iterazioni però, poi la mentre anello sarebbe più appropriato.

Ecco un esempio di un mentre ciclo continuo:

while (Qualcosa == true)


{// codice Loop}

In questo esempio letterale utilizza una variabile booleana chiamata Qualcosa. Se Qualcosa è uguale a vero, il ciclo verrà eseguito.

Naturalmente, se il valore di Qualcosa non cambia mai, il ciclo verrà eseguito all'infinito. Pertanto, è necessario che vi sia una condizione per

modificare il valore di Qualcosa ad un certo punto durante il ciclo. Una volta che questa condizione è vera, Qualcosa viene modificato in falso, e

il ciclo si interrompe l'esecuzione.

Si potrebbe anche incrementare una variabile, proprio come si farebbe con il per operatore:

int contatore = 1; while


(contatore <= 3)
{Contatore ++; }

Questo codice verrà eseguito esattamente come la per ciclo di cui sopra!

L'Ordine Loop

Ecco il codice che useremo per ciclo attraverso il pool di ordini aperti:

per (contatore = 0; contatore <= OrdersTotal () - 1; contatore ++)


{OrderSelect (Counter, SELECT_BY_POS);

// valutare le condizioni}

Noi impostare il valore di contatore a 0, e iterare il ciclo fintanto contatore è minore o uguale al valore di OrdersTotal (), meno uno. contatore
sarà incrementato di 1 dopo ogni iterazione del ciclo.

81
E XPERT UN dvisor P ROGRAMMAZIONE

OrdersTotal () è una funzione che restituisce il numero di ordini attualmente aperte. Perché stiamo sottraendo 1 al valore

della OrdersTotal ()? Spieghiamo come funziona la piscina ordine:

La piscina ordine contiene tutti gli ordini che sono attualmente aperta nel nostro terminale, ivi compresi gli ordini manualmente così
come ordini da consulenti esperti. Gli indici ordine sono numerati a partire da zero. Se c'è un ordine aperto, il suo indice è 0. Quando
un secondo ordine viene aperta, il suo indice è 1. Se un terzo ordine aperto, il suo indice sarà 2, e così via. L'indice 0 è l'ordine più
antico, e l'indice 2 è la più recente.

OrdersTotal () restituirà il numero di ordini attualmente aperte. Nell'esempio di cui sopra, abbiamo tre ordini aperti. Ma perché il nostro

indice degli ordini inizia a 0, vogliamo che il nostro variabile contatore a contare solo per 2. Il valore di contatore deve corrispondere con i
nostri numeri di indice ordine, così che è il motivo per cui dobbiamo sottrarre 1 da OrdersTotal ().

Quando un ordine in piscina ordine aperto viene chiuso, tutti gli ordini nuovi in ​piscina avranno i loro indici di ordine decrementato.
Ad esempio se l'ordine con indice 0 è chiuso, allora l'ordine con indice 1 diventa indice 0, e l'indice di ordine 2 diventa indice 1.
Questo è importante quando si chiude ordini e noi descriveremo più in dettaglio presto.

Torniamo al nostro ciclo ordine: Il OrderSelect () istruzione utilizza il nostro contatore variabile come indice di posizione dell'ordine. Come spiegato

in precedenza, noi aumentare il nostro modo attraverso il pool ordine dall'ordine vecchio al più nuovo. Il SELECT_BY_POS parametro indica che

stiamo selezionando l'ordine dalla sua posizione nella piscina ordine, in contrapposizione al suo numero di biglietti.

Per la prima iterazione di questo ciclo, contatore sarà uguale a 0 e si selezionerà il più antico ordine dalla piscina ordine tramite OrderSelect
(). Possiamo quindi esaminare le informazioni di ordine utilizzando funzioni quali OrderTicket () o OrderStopLoss (), e modificare o

chiudere l'ordine come necessario.

ordine di conteggio

E 'spesso molto utile per scoprire quanti ordini nostro EA ha aperto, e di quale tipo. Creeremo diverse funzioni di conteggio per
contare il numero corrente di ordini aperti, in base al tipo di ordine. La seguente funzione conterà il numero totale di ordini
aperti:

int TotalOrderCount (string argSymbol, int argMagicNumber)


{Int OrderCount;

per (contatore = 0; contatore <= OrdersTotal () - 1; contatore ++)


{OrderSelect (Counter, SELECT_BY_POS);

82
Gestione degli ordini

if (OrderMagicNumber () == argMagicNumber && OrderSymbol () == argSymbol)


{OrderCount ++; }}

ritorno (OrderCount); }

Abbiamo chiamato la nostra funzione di conteggio ordine TotalOrderCount (). Si restituirà un valore intero che indica quanti ordini sono

attualmente aperto sul simbolo grafico specificato che corrisponde al numero magico che abbiamo passato come argomento di funzione.

Iniziamo dichiarando la OrderCount variabile. Dal momento che non abbiamo indicato un valore iniziale,

OrderCount verrà inizializzato come 0. Ritroviamo il per operatore e la OrderSelect ()

funzione dalla sezione precedente.

Dal momento che la piscina ordine contiene tutti gli ordini aperti, compresi quelli collocati da altri EA, è necessario per noi per identificare quali

ordini sono stati collocati dal nostro EA. Controlliamo il OrderSymbol () dell'ordine selezionato per primo, e assicurarsi che corrisponda alla argSymbol

discussione. Il controlliamo il numero magico sull'ordine.

Se OrderMagicNumber () corrisponde al argMagicNumber argomento, si può essere abbastanza sicuro che questo ordine è stato effettuato da

questo EA. Fino a quando l'utente non è in funzione due EA sullo stesso simbolo di valuta con lo stesso numero magico, possiamo essere certi

che questo ordine è stato effettuato da questo EA. Quando l'esecuzione di più consulenti esperti con lo stesso strumento, fare attenzione a

garantire che si sta utilizzando un numero magico unica su ogni EA.

Se l'ordine corrisponde sia il nostro numero magico e il nostro simbolo sulla carta, il valore di OrderCount sarà incrementato di
uno. Dopo aver loop attraverso tutti gli ordini in piscina ordine, si ritorna il valore di OrderCount alla funzione chiamante.

Ecco un esempio di come vorremmo utilizzare questo in codice:

if (TotalOrderCount (simbolo (), MagicNumber)> 0 && CloseOrders == true)


{// Chiude tutti gli ordini}

Se ci sono gli ordini aperti da questo EA, e il valore della CloseOrders è vero ( si suppone questo è stato istituito da qualche altra parte nel programma),

allora il codice all'interno delle parentesi graffe verrà eseguito, che si chiuderà tutti gli ordini aperti.

83
E XPERT UN dvisor P ROGRAMMAZIONE

Andiamo a modificare la nostra routine di conteggio per contare solo acquistare ordini di mercato:

int BuyMarketCount (string argSymbol, int argMagicNumber)


{Int OrderCount;

per (contatore = 0; contatore <= OrdersTotal () - 1; contatore ++)


{OrderSelect (Counter, SELECT_BY_POS);

if (OrderMagicNumber () == argMagicNumber && OrderSymbol () == argSymbol


&& OrderType () == OP_BUY)
{OrderCount ++; }}

ritorno (OrderCount); }

Il codice è identico a prima, se non che abbiamo aggiunto il OrderType () funzione per controllare il tipo di ordine dell'ordine attualmente
selezionata. OP_BUY è la costante che indica un ordine di acquisto di mercato. Per contare altri tipi di ordini, è sufficiente sostituire OP_BUY
con la costante tipo ordine appropriato, e rinominare la funzione di riflettere il tipo di ordine.

Si suggerisce che si crea un ordine funzione di conteggio per ogni tipo di ordine. È possibile visualizzare il codice per tutti l'ordine di
conteggio funzioni nell'Appendice D.

Chiusura ordini multipli

Più spesso che no, avremo bisogno di chiudere ordini multipli dello stesso tipo. Ci uniremo il nostro ciclo ordine con la nostra routine di chiusura

per chiudere più ordini in una sola volta. Questa funzione si chiuderà tutti gli ordini di mercato acquistare depositati dal consulente esperto:

CloseAllBuyOrders nulli (stringa argSymbol, int argMagicNumber, int argSlippage)


{For (int contatore = 0; contatore <= OrdersTotal () - 1; contatore ++)

{OrderSelect (Counter, SELECT_BY_POS);

if (OrderMagicNumber () == argMagicNumber && OrderSymbol () == argSymbol


&& OrderType () == OP_BUY)
{// Chiudi Ordina

int = CloseTicket OrderTicket (); doppie CloseLots =


OrderLots ();

while (IsTradeContextBusy ()) del sonno (10); doppio ClosePrice = MarketInfo


(argSymbol, MODE_BID);

84
Gestione degli ordini

bool Chiuso = OrderClose (CloseTicket, CloseLots, ClosePrice, argSlippage, Rosso);

// Gestione degli errori se


(Closed == false)
{ErrorCode = GetLastError ();

stringa ErrDesc = ErrorDescription (ErrorCode);

stringa ErrAlert = StringConcatenate ( "Chiudi tutte le ordini di acquisto - di errore",


ErrorCode, ":", ErrDesc); Alert (ErrAlert);

stringa ErrLog = StringConcatenate ( "Bid:",


MarketInfo (argSymbol, MODE_BID), "Biglietto:", CloseTicket, "Prezzo:", ClosePrice); Print
(ErrLog); }

altro Counter--; }}}

Si noti che stiamo usando vuoto come tipo di dati funzione. Abbiamo stabilito che non ci sono dati utili per tornare da questa funzione,
quindi non stiamo richiedendo un ritorno operatore nella funzione.

Ritroviamo il per loop e la OrderSelect () funzione dal nostro codice ordine loop. Ci sarà ad anello attraverso il pool ordine ed esaminare ogni

ordine per vedere se abbiamo bisogno di chiuderlo. Se l'ordine corrente è un ordine di acquisto di mercato, come indicato dal OP_BUY, e se

corrisponde il nostro simbolo sulla carta e gli argomenti numero magico, si procederà a chiudere l'ordine.

Chiamiamo il OrderTicket () la funzione per recuperare il numero del biglietto per l'ordine corrente. Da qui, il nostro codice è identico al
codice di buy vicino mercato nei capitoli precedenti. Si noti l'ultima dichiarazione:
Counter--. Se l'ordine è stato chiuso correttamente, il contatore variabile sarà decrementato di uno.

Abbiamo spiegato in precedenza che quando un ordine è chiuso, tutti gli ordini dietro di esso hanno i loro indici decrementato di uno. Se
non decrementa la variabile contatore dopo la chiusura di un ordine, ordini successivi saranno ignorati.

C'è una buona ragione per cui abbiamo ciclo attraverso gli ordini dal più vecchio al più recente: Il regolamento NFA che è andato in vigore

nell'estate del 2009 per i mediatori degli Stati Uniti richiede che più gli ordini effettuati sullo stesso simbolo di valuta sono chiuse nell'ordine

in cui sono stati collocati. Questo è chiamato il FIFO (first in, first out) regola. Scorrendo gli ordini dal più vecchio al più recente ci garantisce

di rispettare la regola FIFO in fase di chiusura degli ordini.

85
E XPERT UN dvisor P ROGRAMMAZIONE

Per chiudere vendita ordini di mercato utilizzando il codice di cui sopra, è sufficiente modificare il tipo di ordine per OP_SELL e il

ClosePrice al simbolo Chiediamo prezzo. La funzione close ordine di vendita può essere visualizzato in Appendice D.

Esaminiamo il codice per chiudere più ordini in sospeso. Questo esempio chiudere tutte acquistare ordini stop. La differenza tra questo codice

e il codice per chiudere ordini di acquisto di mercato di cui sopra è che specifichiamo

OP_BUYSTOP come il nostro tipo di ordine, e usiamo OrderDelete () per chiudere gli ordini.

CloseAllBuyStopOrders nulli (stringa argSymbol, int argMagicNumber, int argSlippage)


{For (int contatore = 0; contatore <= OrdersTotal () - 1; contatore ++)

{OrderSelect (Counter, SELECT_BY_POS);

if (OrderMagicNumber () == argMagicNumber && OrderSymbol () == argSymbol


&& OrderType () == OP_BUYSTOP)
{// Cancella Ordine

int = CloseTicket OrderTicket ();

while (IsTradeContextBusy ()) del sonno (10);

bool Chiuso = OrderDelete (CloseTicket, Rosso);

// Gestione degli errori se


(Closed == false)
{ErrorCode = GetLastError ();

stringa ErrDesc = ErrorDescription (ErrorCode);

stringa ErrAlert = StringConcatenate ( "Chiudere tutti gli ordini Buy Stop",


"- Errore", ErrorCode, ":", ErrDesc); Alert (ErrAlert);

stringa ErrLog = StringConcatenate ( "Bid:",


MarketInfo (argSymbol, MODE_BID), "Chiedi:", MarketInfo (argSymbol, MODE_ASK),
"Biglietto:", CloseTicket); Print (ErrLog); }

altro Counter--; }}}

Questo codice funzionerà per tutti i tipi di ordini in attesa - è sufficiente modificare il confronto di tipo per il tipo di ordine che si desidera chiudere.

L'ordine di funzioni di chiusura per tutti gli ordini pendenti possono essere visualizzati in Appendice D.

86
Gestione degli ordini

Trailing Stop

Possiamo anche utilizzare il nostro ciclo per modificare più ordini. Un esempio comune di questo è la fermata finale. Un trailing stop si muove lo

stop loss alto o in basso con il prezzo ordine come i guadagni di ordine in profitto. Questo "blocca in" profitto e fornisce protezione contro la perdita

eccellente.

Il trailing stop è espresso come numero massimo di semi. Ad esempio, se il trailing stop è di 50 pips, lo stop loss non sarà mai
più di 50 pips di distanza dal prezzo. Se i rovesci dei prezzi e il declino di profitto, lo stop loss rimarrà dove si trova. La fermata
si muove solo nella direzione del profitto - non in senso inverso.

Quando si modifica un trailing stop, dobbiamo controllare per vedere se la distanza in pip tra prezzo corrente e la perdita di arresto
corrente è maggiore che l'arresto finale. In tal caso, la perdita di arresto viene modificato in modo che la distanza dal prezzo corrente in
pip è uguale al numero di semi in posizione di arresto finale.

Il trailing stop viene calcolato in relazione al prezzo di chiusura, che è l'offerta per ordini di acquisto, e Ask For ordini di vendita. Si noti che

questo è l'opposto del prezzo di apertura. Esaminiamo il codice per la modifica di un trailing stop. In primo luogo, si dichiara la variabile

esterna per la nostra impostazione trailing stop:

extern double TrailingStop = 50;

Questo codice controlla tutti acquistare ordini di mercato e modifica lo stop loss, se necessario:

for (int contatore = 0; contatore <= OrdersTotal () - 1; contatore ++)


{OrderSelect (Counter, SELECT_BY_POS);

doppia MaxStopLoss = MarketInfo (Simbolo (), MODE_BID) -


(TrailingStop * PipPoint (Simbolo ()));

MaxStopLoss = NormalizeDouble (MaxStopLoss, MarketInfo (OrderSymbol (), MODE_DIGITS));

doppio CurrentStop = NormalizeDouble (OrderStopLoss (),


MarketInfo (OrderSymbol (), MODE_DIGITS));

// Modifica arresto
if (OrderMagicNumber () == MagicNumber && OrderSymbol () == Simbolo ()
&& OrderType () == OP_BUY && CurrentStop <MaxStopLoss)
{Bool trainati = OrderModify (OrderTicket (), OrderOpenPrice (), MaxStopLoss,

OrderTakeProfit (), 0);

87
E XPERT UN dvisor P ROGRAMMAZIONE

// Gestione degli errori se (trainati


== false)
{ErrorCode = GetLastError ();

stringa ErrDesc = ErrorDescription (ErrorCode);

stringa ErrAlert = StringConcatenate ( "Trailing Stop Buy - Errore",


ErrorCode, ":", ErrDesc); Alert (ErrAlert);

stringa ErrLog = StringConcatenate ( "Offerta:" MarketInfo (Simbolo (), MODE_BID),


"Biglietto:", CloseTicket, "Stop:", OrderStopLoss (), "Trail:", MaxStopLoss); Print (ErrLog); }}}

Dopo aver selezionato l'ordine dalla piscina con OrderSelect (), si determina la distanza massima perdita di arresto sottraendo nostra
posizione di arresto finale, moltiplicato per PipPoint (), dal prezzo di offerta corrente. Questo è memorizzato nella variabile MaxStopLoss.

Usiamo la funzione MQL NormalizeDouble () per arrotondare il MaxStopLoss variabile per il numero corretto di cifre dopo il punto
decimale. Prezzi in MetaTrader possono essere citati fino a otto cifre decimali. Usando NormalizeDouble (), arrotondiamo che
fino a 4 o 5 cifre (2-3 cifre per coppie JPY).

Avanti, recuperiamo lo stop loss dell'ordine attualmente selezionata, e intorno ad esso utilizzando

NormalizeDouble () giusto per essere sicuro. Assegniamo questo valore per la variabile CurrentStop.

Poi controlliamo per vedere se l'attuale ordine deve essere modificato. Se numero magico, simbolo e tipo di ordine corrispondenza, e
lo stop loss corrente ( CurrentStop) è meno di MaxStopLoss, quindi modifichiamo stop loss dell'ordine. Passiamo la MaxStopLoss variabile
come il nostro nuovo stop loss al OrderModify ()
funzione.

Se la OrderModify () funzione non ha avuto successo, la gestione degli errori di routine verrà eseguito, e l'attuale informazioni sui prezzi,

numero di biglietto, stop loss attuale e stop loss modificato verrà stampato al registro.

Le condizioni di trailing stop per ordini di vendita sono diversi, e devono essere affrontati separatamente. Qui ci sono le condizioni per modificare

un ordine di vendita:

// Modifica arresto
if (OrderMagicNumber () == MagicNumber && OrderSymbol () == Simbolo ()
&& OrderType () == OP_SELL && (CurrentStop> MaxStopLoss || CurrentStop == 0))

88
Gestione degli ordini

Si noti la condizione ( CurrentStop> MaxStopLoss || CurrentStop == 0). Se non c'è stop loss disposto con l'ordine, allora la
condizione CurrentStop> MaxStopLoss non sarà mai vero, perché
MaxStopLoss non potrà mai essere inferiore a zero. Così, aggiungiamo una condizione OR, CurrentStop == 0.

Se la perdita di stop dell'ordine corrente è 0 (nessuna perdita di stop), quindi purché le altre condizioni sono vere, il trailing stop verrà

posizionato.

profitto minimo

Facciamo migliorare la nostra trailing stop con l'aggiunta di un livello minimo di profitto. Nell'esempio di cui sopra, il trailing stop entreranno in

gioco subito. Se si imposta uno stop loss iniziale di 100 pips, e il tuo trailing stop è 50 pips, lo stop loss verrebbe impostato a 50 pips subito,

invalidando la vostra perdita iniziale di arresto 100 pip.

L'aggiunta di un livello minimo di profitto vi permetterà di impostare uno stop loss iniziale, mentre ritardando il trailing stop fino al raggiungimento di

una determinata quantità di profitto. In questo esempio, supponiamo che uno stop loss iniziale di 100 pip viene impostato quando è ordinato.

Stiamo utilizzando un trailing stop di 50 pips, con un livello minimo di profitto di 50 pips. Quando il profitto per l'ordine raggiunge 50 pips, lo stop

loss verrà regolato per andare in pari.

Aggiungiamo una variabile esterna per la nostra impostazione di profitto minimo:

extern int TrailingStop = 50;


extern int MinimumProfit = 50;

La seguente funzione modifica la perdita di arresto per tutti acquistare ordini di mercato, controllando il profitto minimo prima di farlo:

vuoto BuyTrailingStop (stringa argSymbol, int argTrailingStop, int argMinProfit,


int argMagicNumber)
{For (int contatore = 0; contatore <= OrdersTotal () - 1; contatore ++)

{OrderSelect (Counter, SELECT_BY_POS);

// Calcolare Max Stop and Min Profit


doppia MaxStopLoss = MarketInfo (argSymbol, MODE_BID) -
(TrailingStop * PipPoint (argSymbol));

MaxStopLoss = NormalizeDouble (MaxStopLoss,


MarketInfo (OrderSymbol (), MODE_DIGITS));

doppio CurrentStop = NormalizeDouble (OrderStopLoss (),


MarketInfo (OrderSymbol (), MODE_DIGITS));

89
E XPERT UN dvisor P ROGRAMMAZIONE

doppia PipsProfit = MarketInfo (argSymbol, MODE_BID) - OrderOpenPrice (); doppio MinProfit = MinimumProfit
* PipPoint (argSymbol));

// Modifica arresto
if (OrderMagicNumber () == argMagicNumber && OrderSymbol () == argSymbol
&& OrderType () == OP_BUY && CurrentStop <MaxStopLoss && PipsProfit> = MinProfit)

{Bool trainati = OrderModify (OrderTicket (), OrderOpenPrice (), MaxStopLoss,

OrderTakeProfit (), 0);

// Gestione degli errori se (trainati


== false)
{ErrorCode = GetLastError ();

stringa ErrDesc = ErrorDescription (ErrorCode);

stringa ErrAlert = StringConcatenate ( "Trailing Stop Buy - Errore",


ErrorCode, ":", ErrDesc); Alert (ErrAlert);

stringa ErrLog = StringConcatenate ( "Bid:",


MarketInfo (argSymbol, MODE_BID), "Biglietto:", CloseTicket, "Stop:", OrderStopLoss (),
"Trail:", MaxStopLoss); Print (ErrLog); }}}}

Si calcola il profitto attuale ordine in pips sottraendo OrderOpenPrice () dal prezzo di offerta attuale, e la memorizzazione che nella
variabile PipsProfit. Confrontiamo che, per la nostra impostazione di profitto minimo, che viene moltiplicato per PipPoint () e
memorizzato nella variabile MinProfit.

Se il risultato corrente in pips ( PipsProfit) è maggiore o uguale al nostro profitto minimo ( MinProfit), e tutte le altre
condizioni sono vere, la fermata sarà modificato.

Il trailing stop con l'impostazione minima di profitto è molto più flessibile, in modo da probabilmente desidera utilizzare questa funzione nel vostro

consulente esperto. Vedi Appendice D per il codice completo sell stop finale.

Break Even Smettere

È inoltre possibile utilizzare questo metodo per applicare una pausa addirittura fermare adeguamento ai vostri ordini. Un pareggio regola di

arresto lo stop loss a essere pari al prezzo di apertura ordine, dopo un certo livello di profitto è stato raggiunto. Il pareggio di arresto è

indipendente dal tuo stop loss iniziale e le funzioni di trailing stop.

90
Gestione degli ordini

Qui è la variabile esterna per la nostra vacanza, anche l'impostazione di profitto. Il profitto minimo è specificato in pips.

extern double BreakEvenProfit = 25;

Questo codice modificherà lo stop loss su tutti gli ordini di acquisto di mercato per rompere anche, una volta che l'ordine di profitto in pip è uguale o

superiore a BreakEvenProfit. Non sarà la creazione di una funzione per questo, ma è possibile farlo se si sente che sarebbe utile.

for (int contatore = 0; contatore <= OrdersTotal () - 1; contatore ++)


{OrderSelect (Counter, SELECT_BY_POS);

RefreshRates ();

doppia PipsProfit = Bid ​- OrderOpenPrice ();


doppio MinProfit = BreakEvenProfit * PipPoint (OrderSymbol ()));

if (OrderMagicNumber () == MagicNumber && OrderSymbol () == Simbolo ()


&& OrderType () == OP_BUY && PipsProfit> = MinProfit && OrderOpenPrice ()! =
OrderStopLoss ())
{Bool pareggio = OrderModify (OrderTicket (), OrderOpenPrice (),

OrderOpenPrice (), OrderTakeProfit (), 0);

if (pareggio == false)
{ErrorCode = GetLastError ();

stringa ErrDesc = ErrorDescription (ErrorCode);

stringa ErrAlert = StringConcatenate ( "Buy Break Even - Errore",


ErrorCode, ":", ErrDesc); Alert (ErrAlert);

stringa ErrLog = StringConcatenate ( "Offerta", Bid, "Chiedi:" Chiedi,


"Biglietto:", CloseTicket, "Stop:", OrderStopLoss (), "Pausa", MinProfit); Print (ErrLog); }}}

Sottraiamo prezzo di apertura dal prezzo di offerta corrente la fine di calcolare il profitto corrente in pips, e memorizziamo questo PipsProfit.
Si calcola il profitto minimo in pips e memorizziamo che nel MinProfit.
Se PipsProfit è più grande di O uguale a MinProfit, allora Noi modificare lo stop loss pari al prezzo di apertura ordine.

Controlliamo anche fare in modo che lo stop loss non è già impostato al pareggio prezzo. Se
OrderOpenPrice () è diverso da OrderStopLoss (), allora possiamo procedere.

91
E XPERT UN dvisor P ROGRAMMAZIONE

Aggiornamento del Expert Advisor

Andiamo a modificare il inizio() funzione del nostro movimento consulente media croce esperti per riflettere le nuove funzioni che abbiamo creato. In primo

luogo, si provvederà a controllare per vedere se ci sono eventuali ordini di acquisto aperti prima di aprire di più. Invece di chiudere un unico ordine di

vendita, ci limiteremo a utilizzare la funzione di chiudere tutti gli ordini di vendita. Questo metodo non ci richiede di usare un biglietto ordine.

// Acquistare Order
if (FastMA> SlowMA && BuyTicket == 0 && BuyMarketCount (Simbolo (), MagicNumber) == 0)
{ if (SellMarketCount (Simbolo (), MagicNumber)> 0)

{CloseAllSellOrders (Simbolo (), MagicNumber, lo slittamento); }

SellTicket = 0;

BuyTicket = OpenBuyOrder (Simbolo (), Misura di lotto, UseSlippage, MagicNumber); }

Abbiamo usato la funzione BuyMarketCount () che abbiamo definito a pagina 84 per restituire il numero di ordini di acquisto attualmente aperti. Vi

terremo il Comprare un biglietto check-in, in modo che solo alternati gli ordini di acquisto / vendita sono aperti.

La funzione CloseAllSellOrders () chiude eventuali ordini di vendita che sono aperti. controlliamo

SellMarketCount () prima di vedere se ci sono eventuali ordini di vendita per chiudere. Questa funzione non richiede un biglietto di ordine, a

differenza del CloseSellOrder () funzione nel capitolo 4. Si consiglia di utilizzare questo metodo per chiudere gli ordini opposti nel vostro EA, in

quanto è più robusto.

Il resto del codice di posizionamento buy ordine è la stessa di prima. Il codice di posizionamento ordine di vendita corrispondente è qui

sotto:

// Sell Order
if (FastMA <SlowMA && SellTicket == 0 && SellMarketCount (Simbolo (), MagicNumber) == 0)
{ if (BuyMarketCount (Simbolo (), MagicNumber)> 0)

{CloseAllBuyOrders (Simbolo (), MagicNumber, lo slittamento); }

BuyTicket = 0;

SellTicket = OpenSellOrder (Simbolo (), Misura di lotto, UseSlippage, MagicNumber); }

92
Gestione degli ordini

Avanti, aggiungiamo le funzioni trailing stop al nostro ordine. Ci eseguire la routine trailing stop dopo il nostro dell'ordine. Come sopra, noi

controllerà per acquisto aperto o vendere gli ordini prima di chiamare la funzione di trailing stop. Aggiungiamo le seguenti variabili esterne al

nostro EA:

extern int TrailingStop = 50; extern int


MinimumProfit = 50;

Questo è il codice per controllare e modificare le fermate finali. Si noti che controlliamo per vedere se c'è una voce per il TrailingStop ambientazione.

Se è impostato su 0, si è in effetti disabilitato:

if (BuyMarketCount (Simbolo (), MagicNumber)> 0 && TrailingStop> 0)


{BuyTrailingStop (Simbolo (), TrailingStop, MinimumProfit, MagicNumber); }

if (SellMarketCount (Simbolo (), MagicNumber)> 0 && TrailingStop> 0)


{SellTrailingStop (Simbolo (), TrailingStop, MinimumProfit, MagicNumber); }

È possibile visualizzare questi cambiamenti nel contesto in Appendice C.

93
E XPERT UN dvisor P ROGRAMMAZIONE

Capitolo 6
Ordine Condizioni e indicatori

Abbiamo passato gli ultimi capitoli Creazione di funzioni che svolgono i meccanismi di ordine che sono comuni ad ogni consulente esperto. Queste

funzioni sono destinate ad essere utilizzato in una varietà di situazioni commerciali, e deve essere il più riutilizzabile e flessibile possibile. Questo ci

permette di concentrarci sulla codifica le condizioni commerciali uniche per il nostro sistema di trading.

Questo è dove la maggior parte del tuo lavoro sta per essere messo a fuoco - ricevendo il consulente esperto di commerciare il sistema nel modo più accurato

possibile. Avremo bisogno di identificare le esatte condizioni per l'apertura e la chiusura degli ordini, così come la determinazione di stop loss e prendere i prezzi

di profitto. Quasi tutti i sistemi di negoziazione si avvale di prezzo e / o indicatore di dati. Esaminiamo i modi in cui possiamo accedere e utilizzare queste

informazioni nei nostri consulenti esperti.

I dati sui prezzi

Insieme con l'attuale Bid o Richiedi prezzo (che abbiamo già trattato nei capitoli precedenti), potrebbe essere necessario utilizzare i dati dei

prezzi bar, vale a dire la alto, basso, aperto o vicino di un particolare bar. Per la tabella corrente, è possibile utilizzare gli array della serie

predefinite Alto [], Basso [], Open [] e Vicino[].

Un array è una variabile che contiene più valori. È scorrere i valori modificando l'indice, che è contenuta nelle parentesi quadre.
Per esempio Aprire [0] è il prezzo di apertura della barra corrente. 0 è l'indice, e cambiandolo, possiamo ottenere il prezzo di
apertura di altri bar. Barra precedente alla barra corrente dovrebbe avere un indice di 1, e così via. Saremo spesso utilizzando la
barra di corrente o valori dei prezzi del bar precedente.

Se avete bisogno di un alto, basso, aprire o chiudere il valore di un simbolo diverso da quello grafico corrente, o se avete bisogno di dati sui prezzi

per un periodo diverso dal periodo grafico corrente, è possibile utilizzare le funzioni IHIGH (), ILOW (), apro() e io chiudo(). Ecco la sintassi di queste

funzioni, utilizzando io chiudo() come il nostro esempio:

doppia IChiudere (string Simbolo, int Periodo, int Cambio)

• Simbolo - Il simbolo della coppia di valute da utilizzare.

• Periodo - Il periodo del grafico da utilizzare, in pochi minuti.

• Cambio - Il passaggio all'indietro rispetto alla barra corrente.

94
Ordine Condizioni e indicatori

Usiamo io chiudo() per ottenere un prezzo vicino per un diverso periodo di grafico. Per esempio, stiamo usando un grafico a 1 ora, ma vogliamo

controllare il prezzo di chiusura della barra precedente sul grafico a 4 ore:

doppio H4Close = IChiudere (NULL, PERIOD_H4,1);

NULLO si riferisce al simbolo grafico corrente. PERIOD_H4 è una costante intera che si riferisce al periodo del grafico H4. 1 è il nostro turno,

che è la barra precedente alla barra corrente. Usiamo un altro esempio che restituisce la chiusura della barra corrente su un altro grafico:

doppia GBPClose = IChiudere (GBPUSD, 0,0);

GBPUSD è il simbolo che stiamo usando. Abbiamo specificato 0 come il nostro periodo, in modo che il periodo del grafico stiamo controllando su GBPUSD sarà

la stessa come nostra tabella corrente. Lo spostamento è 0, che è la barra corrente.

È possibile utilizzare un operatore di ciclo, come per o mentre per incrementare il Cambio parametri e scorrere la storia delle classifiche.

Questo per ciclo recupera il prezzo di chiusura per ciascuno degli ultimi dieci bar, e lo stampa al registro:

for (int count = 0; Count <= 9; Conteggio ++)


{Double CloseShift = IChiudere (NULL, 0, Conte);

Stampa (Count +" "+ CloseShift); }

indicatori

La maggior parte dei sistemi di negoziazione utilizza indicatori per determinare i segnali commerciali. MetaTrader comprende oltre 20 indicatori

comuni, tra media mobile, MACD, RSI e stocastico. MQL ha funzioni built-in per gli indicatori azionari. È inoltre possibile utilizzare indicatori

personalizzati nel vostro consulente esperto.

indicatori di tendenza

Diamo uno sguardo al l'indicatore abbiamo usato in questo libro: la media mobile. La media mobile è un tendenza indicatore.
Essa mostra se il prezzo si è spostato verso l'alto o verso il basso per il periodo dell'indicatore. La media mobile è costituito da
una singola linea tracciata sul grafico che mostra il prezzo medio negli ultimi X numero di barre.

Ecco la sintassi per la funzione media mobile:

95
E XPERT UN dvisor P ROGRAMMAZIONE

doppia iMA (string Simbolo, int Lasso di tempo, int MAPeriod, int MAShift, int MAMethod,
int MACOSTI, int Cambio)

• Simbolo - Il simbolo del grafico di applicare la media mobile a.

• Lasso di tempo - Il periodo di tempo del grafico di applicare la media mobile a.

Ogni funzione indicatore MQL inizia con questi due parametri. Dopo di ciò sono i parametri indicatorspecific. Queste
corrispondono al contenuto del parametri linguetta nel proprietà di indicatore.

• MAPeriod - Il periodo di look-retro della media mobile.

Quasi ogni indicatore ha almeno un parametro periodo. La maggior parte degli indicatori sono calcolati utilizzando una serie di prezzi prese dai bar

precedenti. Ad esempio, un'impostazione periodo di 10 significherebbe che l'indicatore utilizza i dati dei prezzi degli ultimi dieci barre per calcolare

il valore dell'indicatore.

• MAShift - Lo spostamento in avanti della linea di media mobile, nei bar. Questo è diverso da quello
Cambio parametro di seguito.

• MAMethod - Il metodo di calcolo della media mobile. Scelte includono semplice, esponenziale, levigata o
lineare ponderata.

Ogni indicatore che utilizza una media mobile può darvi la possibilità di scegliere il metodo di calcolo MA. Parleremo di
movimento metodi media più avanti nel capitolo.

• MACOSTI - L'array prezzo da utilizzare nel calcolo della media mobile.

Questo può essere stretta, aperto, alto, basso o qualche tipo di media; come mediano, tipico o prezzi ponderati. Discuteremo costanti
dei prezzi applicati più avanti nel capitolo.

• Cambio - Lo spostamento all'indietro della barra per restituire il calcolo.

Il Cambio parametro è il parametro finale in ogni funzione dell'indicatore. Questo è l'indice della barra per restituire il valore indicatore. Un
valore pari a 0 restituisce il valore dell'indicatore della barra corrente. Un valore di 3 restituirà il valore dell'indicatore da 3 bar fa.

Gli indicatori medi e simili in movimento sono disegnate direttamente sulla carta. È possibile creare le condizioni commerciali basate sul
rapporto tra indicatori e prezzo. Nostra croce media mobile è un esempio di un rapporto di prezzo tra due indicatori. Quando il prezzo uno
dell'indicatore è maggiore rispetto agli altri, un segnale di acquisto o di vendita viene generato.

96
Ordine Condizioni e indicatori

Si potrebbe anche generare segnali di commercio, quando il prezzo corrente passa sopra o sotto una linea di indicazione. Ad esempio,
l'indicatore Bande Bollinger può essere utilizzato per generare segnali di trading in base alla posizione del prezzo rispetto alle bande
superiori e inferiori.

Oscillatori

L'altro tipo principale di indicatore è un oscillatore. Oscillatori sono disegnati in una finestra separata, e come suggerisce il nome,
oscillano tra estremi alto e basso prezzo. Oscillatori sono entrambi centrati attorno ad un asse neutro (generalmente 0), oppure
sono legati da un estremo superiore o inferiore (ad esempio 0 e 100). Esempi di oscillatori di momentum includono, Stocastico e
RSI.

Oscillatori indicano ipercomprato e ipervenduto livelli. Mentre possono essere usati come un indicatore di tendenza, essi sono generalmente utilizzati per

individuare zone di inversione attesa. Questi sono utilizzati per la produzione di controtendenza

segnali di trading.

Diamo un'occhiata a un oscillatore popolare, il Stocastico. Stocastico è costituito da due linee, la linea stocastico (chiamata anche
la linea K%), e la linea di segnale (la linea% D). Lo stocastico oscilla tra 0 e
100. Quando lo stocastico è superiore a 70, si dice essere ipercomprato, e in attesa di una possibile inversione. Se è inferiore a 30, si dice di

essere ipervenduto.

Ecco la sintassi per l'indicatore stocastico:

doppia iStochastic (string Simbolo, int Lasso di tempo, int K Periodo, int Dperiod, int rallentare,
int MAMethod, int PriceField, int Modalità, int Cambio)

Siamo già familiarità con i primi due parametri, Simbolo e Lasso di tempo. Esaminiamo i parametri specifici indicatori:

• KPeriod - Il periodo per la linea% K.

• DPeriod - Il periodo per la linea% D.

• rallentare - Il valore di rallentamento per lo stocastico. Un valore inferiore indica una stocastico veloce, mentre un valore
elevato indica uno lento.

• MAMethod - La linea% D ha un metodo della media mobile applicata ad esso. Questa è la stessa impostazione
della media mobile. Esamineremo i metodi media mobile a breve.

• PriceField - Determina i dati sui prezzi utilizzati per la linea% K. Questo è o 0: Low / High o 1: Chiudi / Chiudi. Un valore pari a 1
rende più probabile che lo stocastico saranno negoziate al suo estremi.

• Modalità - Determina la linea stocastico per calcolare - linea K%,: 1 o 2:% linea D.

97
E XPERT UN dvisor P ROGRAMMAZIONE

Prendiamo un momento per parlare del Modalità parametro. Alcuni indicatori disegnare più linee nel grafico. Lo stocastico ha due.
Avremo bisogno di chiamare il iStochastic () funzione per entrambe le linee% K e% D, come illustrato di seguito:

doppia KLine = iStochastic (NULL, 0, KPeriod, DPeriod, rallentando, MAMethod, Prezzo, 0,0); doppia LINEAD = iStochastic (NULL,
0, KPeriod, DPeriod, rallentando, MAMethod, Prezzo, 1,0);

Si noti che il Modalità parametro è 0 per la linea% K, e 1 per la linea% D. L'argomento MQL di riferimento,
Costanti standard - Linee Indicator elenca le costanti intere validi per i vari indicatori che utilizzano la Modalità parametro.

È possibile generare segnali commerciali basate sul rapporto fra le linee indicatrici e certi livelli indicatori, quali i livelli di
ipercomprato e ipervenduto rispettivamente 70 e 30,. È inoltre possibile valutare i segnali commerciali sulla base di rapporti
l'indicatore righe gli uni agli altri. Ad esempio, si può decidere di aprire un ordine di acquisto solo quando la linea% K è sopra la
linea% D. Qui ci sono alcune condizioni di esempio:

if (KLine <70) // Acquistate se stocastico non è ipercomprato se (KLine> LINEAD) //


Acquistare se% K è maggiore di% D

Le funzioni dell'indicatore incorporate sono in riferimento MQL sotto indicatori tecnici. Se desideri ulteriori informazioni
sull'utilizzo di un indicatore o metodo di calcolo, consultare la sezione di analisi tecnica del sito a MQL http://ta.mql4.com/.

indicatori personalizzati

Centinaia di indicatori personalizzati per MetaTrader sono disponibili online. Se si decide di utilizzare un indicatore personalizzato nel vostro

consulente esperto, un po 'di noia dovrà essere fatto. E 'meglio se avete la. mq4

file di codice sorgente quando si utilizza un indicatore personalizzato. Mentre è possibile utilizzare un indicatore personalizzato senza di essa,

avente il codice sorgente renderà facile capire gli indici tampone per la Modalità parametro.

MQL ha una funzione built-in per la gestione di indicatori personalizzati - iCustom (). Ecco la sintassi:

doppia iCustom (string Simbolo, int Lasso di tempo, stringa IndicatorName, Indicatore Parametri,
int Modalità, int Cambio);

Sei già familiarità con Simbolo, Temporale, modalità e Cambio dalla precedenza nel capitolo. Iniziamo con IndicatorName. Questo è il
nome del file dell'indicatore, esattamente come appare nella indicatori personalizzati elenco nella Navigatore finestra. Ad esempio,
"Slope Direction Line", o "super_signal".

98
Ordine Condizioni e indicatori

parametri indicatori è dove inseriamo i parametri per l'indicatore personalizzato. Il ingressi linguetta nel Proprietà indicatore

personalizzato finestra mostrerà i parametri per l'indicatore personalizzato. Le icone a sinistra di ogni parametro indicheranno
il tipo di dati. Se non si ha il. mq4 file per un indicatore, si dovrà determinare i parametri indicatori di questa finestra di dialogo.

Fig 6.1 - La finestra di dialogo di input indicatore personalizzato

Un modo più semplice di trovare dei parametri è quello di verificare la extern variabili all'inizio del file di codice sorgente indicatore. Tutti i
parametri indicatori, i loro tipi di dati e valori di default saranno elencati qui, si può semplicemente copiare e incollare questo codice alla
sezione variabili esterne del vostro consulente esperto.

Ogni variabile esterna in un indicatore personalizzato deve avere un parametro di controparte nella
iCustom () funzione, e devono essere nell'ordine in cui sono visualizzati l'indicatore. È possibile utilizzare una costante per i parametri che

non hanno bisogno di essere cambiato (come stringhe informativi, o impostazioni non essenziali).

Ecco un esempio: L'indicatore personalizzato popolare Slope direzione della linea ha queste variabili esterni elencati nel codice sorgente.

Creeremo le variabili esterne per queste impostazioni nel nostro consulente esperto:

// ---- Parametri di input extern int


periodo = 80;
extern int method = 3; // MODE_SMA
extern int prezzo = 0; // PRICE_CLOSE

99
E XPERT UN dvisor P ROGRAMMAZIONE

Useremo gli identificatori SlopePeriod, SlopeMethod e SlopePrice per le variabili esterne nel nostro consulente esperto.

// esterno int variabili extern SlopePeriod = 80;


extern int SlopeMethod = 3; extern int
SlopePrice = 0;

Ecco come il iCustom () Funzione cercherà questo particolare indicatore, insieme alle variabili esterne:

iCustom (NULL, 0, "Slope Direction Line", SlopePeriod, SlopeMethod, SlopePrice, 0,0);

NULLO indica che stiamo usando il simbolo grafico corrente, e 0 è il periodo grafico corrente. " Slope direzione della linea" è il

nome del file dell'indicatore. SlopePeriod, SlopeMethod e SlopePrice


sono i tre parametri indicatori. Stiamo usando il default Modalità indice di 0, e il Cambio è la barra corrente.

Sebbene l'indicatore di direzione linea Slope è disegnata come una singola linea, è in realtà costituito da due tamponi
differenti. A seconda che il prezzo indicatore si muove su o giù, il colore (e il buffer) cambiamento.

Se si collega l'indicatore a un grafico e visualizzare il finestra dati in MetaTrader, vedrete due

valori per la Linea pendenza Direzione. Il primo valore visualizza un prezzo quando il valore

dell'indicatore è in aumento. La linea è blu per impostazione predefinita. Il secondo valore

visualizza un prezzo quando il valore dell'indicatore è in diminuzione. Questa linea è rossa

per impostazione predefinita.

Abbiamo bisogno di determinare il Modalità indice per entrambe le linee. Il modo più

semplice per farlo è quello di guardare il codice sorgente. Nel dentro() funzione, si

vedrà diverse righe di codice che vengono utilizzati per dichiarare e impostare le

proprietà dell'indicatore buffer:

Fig 6.2 - Finestra Dati

SetIndexBuffer (0, Uptrend); SetIndexBuffer (1,


Dntrend); SetIndexBuffer (2, ExtMapBuffer);

. . .
SetIndexStyle (0, DRAW_LINE, STYLE_SOLID, 2); SetIndexStyle (1,
DRAW_LINE, STYLE_SOLID, 2);

100
Ordine Condizioni e indicatori

Il primo SetIndexBuffer () funzione imposta un buffer indicatore con indice 0, e utilizza l'array
Trend rialzista. Possiamo intuire dal nome matrice che questo vale per la linea indicatore blu. La seconda funzione fa altrettanto per per la

matrice DnTrend. Notare la SetIndexStyle () funzioni nella parte inferiore che imposta buffer 0 e 1 per disegnare una linea continua.

Il terzo tampone, con l'indice 2 e la matrice ExtMapBuffer, viene utilizzato solo per il calcolo. Possiamo quindi concludere che 0 e 1
sono gli indici di buffer che contengono nostre informazioni prezzo indicatore. Sulla base delle identificatori di matrice, 0 è la linea
uptrend, e 1 è il ribasso. Ecco come dichiariamo i nostri indicatori:

doppia SlopeUp = iCustom (NULL, 0, "Slope Direction Line", SlopePeriod, SlopeMethod,


SlopePrice, 0,1);

doppia SlopeDown = iCustom (NULL, 0, "Slope Direction Line", SlopePeriod, SlopeMethod,


SlopePrice, 1,1);

Si noti che il Modalità parametro - il penultimo - è stata impostata l'indice indicatore tampone appropriato - 0 per SlopeUp, e 1 per
SlopeDown. Il Cambio parametro - l'ultima quella - è stato impostato su 1, che controlla il valore dell'ultima asta di chiusura.

E 'una buona idea di verificare che si sta utilizzando il corretto Modalità parametri. Aggiungere un Stampare()

funzione per il vostro consulente esperto, ed eseguire un test di nuovo nel Tester strategia utilizzando "solo i prezzi Aperte", come il modello di prova.

Assicurarsi che il Cambio parametro è impostato a 1 nella iCustom () funzione.

Stampa ( "Slope Up: "+ SlopeUp +", Slope Down: "+ SlopeDown +" Time:" + TimeToStr (Time [1]));

Il Stampare() funzione stampa il valore dei nostri indicatori buffer al registro, insieme con la data e l'ora della barra precedente. È
possibile visualizzare il registro sotto la rivista scheda nella finestra Strategy Tester. Ecco l'output del Stampare() funzione nel
registro:

Slope Up: 2147483647,00 milioni, scendono: 1,50,4839 milioni Time: 2009/11/26 16:00

Il valore per SlopeUp, 2147483647, è un grande numero intero che rappresenta il empty_value stato di un indicatore personalizzato. Si può

effettivamente utilizzare questo come una condizione di trading. SlopeDown restituisce il valore dell'indicatore della barra precedente. Tempo indica

la barra che vogliamo trovare sul grafico.

Clicca il aperto Grafico pulsante nella finestra Tester strategia per aprire un grafico con l'indicatore già applicato. Trova la barra indicato nel

registro per Tempo, e assicurarsi che i valori degli indicatori nella finestra dei dati corrispondono a quelli stampati nel registro. In caso

contrario, regolare il Modalità parametro nel iCustom ()

funzione fino a trovare il tampone corretto.

101
E XPERT UN dvisor P ROGRAMMAZIONE

Ecco come useremmo l'indicatore della linea pendenza di direzione nel nostro consulente esperto. Se la pendenza è trend verso l'alto, SlopeUp

restituirà un valore di prezzo, mentre SlopeDown tornerà empty_value, o

vale 2147483647. L'opposto quando la pendenza è orientata verso il basso.

if (SlopeUp! = empty_value && SlopeDown == empty_value) // Acquistare se (SlopeUp == empty_value


&& SlopeDown! = empty_value) // Vendi

Queste condizioni semplicemente controllare per vedere quale linea è uguale a empty_value, e che la linea non è.

Indicatore costanti di tempo

Frames

Molte funzioni in MQL, comprese le funzioni di indicatori e di prezzo, accettare un parametro di tempo. Come indicato in precedenza, se
usiamo un Lasso di tempo parametro di 0, verrà utilizzato il frame corrente tempo grafico. Se vogliamo usare un diverso lasso di tempo,
avremo bisogno di specificare l'intervallo di tempo in minuti. Ad esempio, M5 è 5, H1 è 60 e H4 è 240. Possiamo anche utilizzare costanti
per indicare i tempi:

• PERIOD_M1 - 1 minuto.

• PERIOD_M5 - 5 minuti.

• PERIOD_M15 - 15 minuti.

• PERIOD_M30 - 30 minuti.

• PERIOD_H1 - 1 ora (60 minuti).

• PERIOD_H4 - 4 ore (240 minuti).

• PERIOD_D1 - Tutti i giorni (1440 minuti).

Prezzo Applied

Il parametro indicatore prezzo riservato indica la serie prezzo da utilizzare nel calcolo del valore dell'indicatore. Sarà generalmente
utilizzare il vicino per calcolare i valori degli indicatori, anche se si potrebbe desiderare di utilizzare altri valori. Ecco l'elenco delle
serie dei prezzi e le costanti associate, insieme al valore intero:

• PRICE_CLOSE - 0: Chiudere prezzo.

• PRICE_OPEN - 1: prezzo di apertura.

• PRICE_HIGH - 2: prezzo elevato.

102
Ordine Condizioni e indicatori

• price_low - 3: prezzo basso.

• PRICE_MEDIAN - 4: prezzo mediano, ( Alto + Basso) / 2.

• PRICE_TYPICAL - 5: Il prezzo tipico, ( High + Low + Chiudi) / 3.

• PRICE_WEIGHTED - 6: prezzo ponderata, ( High + Low + Chiudi + Chiudi) / 4.

Moving Metodi media

Indicatori che utilizzano una media mobile come parte del loro calcolo può avere un parametro per regolare il metodo di calcolo
della media mobile. La linea di media mobile sarà disegnata in modo diverso a seconda del metodo di calcolo. Questi sono gli
movimento costanti medi metodo con i valori interi corrispondenti:

• MODE_SMA - 0: media mobile semplice. Calcola la media dei dati sui prezzi.

• MODE_EMA - 1: media mobile esponenziale. Dà più peso ai dati sui prezzi recenti, e in modo esponenziale meno peso ai dati
sui prezzi più anziani. Una media mobile molto popolare.

• MODE_SMMA - 2: media mobile lisciata. Una media mobile semplice calcolato con un'equazione lisciatura. Crea
una linea regolare, ma meno reattivo.

• MODE_LWMA - 3: lineare ponderata media mobile. Simile alla media mobile esponenziale, ma dà maggiore
peso al prezzo più recente.

Valutare Condizioni commerciali

Usiamo gli operatori condizionali Se e altro per valutare le nostre condizioni commerciali. Hai già visto queste usata in questo libro, ma per
voi i nuovi programmatori, una breve recensione è in ordine.

Il Se operatore valuta una condizione vera o falsa. Se la condizione è vera, il codice subito dopo il Se istruzione viene
eseguita. Se la condizione è falsa, salterà avanti per il codice che segue il blocco if:

if (BuyCondition == true)
{OpenBuyOrder (...); }

Se v'è un solo economico a seguito della Se operatore, può essere scritto in questo modo:

if (BuyCondition == true) OpenBuyOrder (...);

103
E XPERT UN dvisor P ROGRAMMAZIONE

Più istruzioni devono essere racchiusi tra parentesi graffe.

Il altro operatore valuta una condizione alternativa, a condizione che il precedente Se statement (s) sono false. È possibile combinare altro
e Se per creare una condizione di alternativo che verrà eseguito solo se è vero.

Ad esempio, questo codice valutazione tre condizioni in ordine. Se uno di loro è vero, sarà eseguito solo quel blocco di codice. Se
nessuno di loro sono vere, sarà eseguita nessuna di esse:

if (Condizione1 == true) // Eseguire condizione 1


else if (Condizione2 == true) // Esegue condizione 2 else if (Condizione3 == true) //
Eseguire condizione 3

Il altro operatore può essere utilizzato da solo al termine di un se altro sequenza per indicare una condizione che sarà eseguito
per default se tutti gli altri operatori se sono false. Come sopra, sarà eseguito solo una delle condizioni:

if (Condizione1 == true) // Eseguire condizione 1


else if (Condizione2 == true) // Esegue condizione 2 altro

{// Esegue condizione 3 se 1 e 2 sono false}

Se si dispone di più Se operatori senza alcuna altro operatori, ognuno verranno eseguiti se è vero - non importa se la successiva Se
affermazione è vera o falsa:

if (Condizione1 == true) // Esegue condizione 1 se (Condizione2 == true) //


Eseguire condizione 2

Operazioni relazioni

Iniziamo valutando condizioni veri e falsi da valori confrontando usando maggiore, minore, uguale, non uguale e così via.
Ecco un elenco di operazioni di relazione:

• == Uguale a - Se x == y, la condizione è vera.

• > Più grande di - Se x> y, la condizione è vera.

• < Meno di - Se x <y, la condizione è vera.

• > = Maggiore o uguale a - Se x> = y, la condizione è vera.

104
Ordine Condizioni e indicatori

• <= Minore o uguale a - Se x <= y, la condizione è vera.

• ! = Non uguale a - Se x! = y, la condizione è vera.

Si noti che l'operatore uguale (==) non è la stessa come l'operatore di assegnazione (=)! L'operatore di assegnazione viene utilizzata quando si

assegna un valore a una variabile. L'uguale operatore viene utilizzato per valutare un vero falso condizione /. Questo è un errore di sintassi comune, e

quello che si dovrebbe guardare fuori per.

È possibile confrontare due valori, purché siano dello stesso tipo di dati. È possibile confrontare un valore booleano alle
costanti vero o falsa. È possibile confrontare una stringa, intero o doppia variabile a un valore costante appropriata, o ad un'altra
variabile dello stesso tipo.

Operazioni booleane

Usiamo gli operatori booleani AND (&&) e OR (||) per combinare le operazioni di relazione. L'operatore AND valuta se tutte
le condizioni sono vere. Se è così, l'intera istruzione è vera. Se una delle condizioni sono false, l'intera istruzione è falsa.

if (BooleanVar1 == true && Indicator1> Indicator2)


{ // Ordine aperto }

Se BooleanVar1 è uguale a true, e Indicator1 è più grande di Indicator2, la dichiarazione restituisce vero, e il codice tra le parentesi
viene eseguito. Se una di queste condizioni sono false, l'intera istruzione restituisce falso, e il codice nelle parentesi non viene
eseguito. Non ci può essere un numero qualsiasi di condizioni combinate insieme con l'operatore &&, e tutti devono valutare a
true.

L'operatore OR valuta se una qualsiasi delle condizioni sono vere. Se almeno una condizione è vera, l'intera istruzione
restituisce vero. Se tutte le condizioni sono false, l'istruzione restituisce falsa.

if (BooleanVar1 == true || Indicator1> Indicator2)

Se uno dei due BooleanVar1 è uguale a true, o Indicator1 è più grande di Indicator2, la dichiarazione è valutato a vero. Se
entrambe queste condizioni sono false, l'istruzione restituisce falsa.

È possibile combinare AND e OR operazioni per creare condizioni di mercato più complesse. Nel fare ciò, utilizzare le parentesi per
stabilire l'ordine delle operazioni.

105
E XPERT UN dvisor P ROGRAMMAZIONE

if ((BooleanVar1 == true && Indicator1> Indicator2) || BooleanVar1 == false)

La dichiarazione ( BooleanVar1 == true && Indicator1> Indicator2) viene valutata prima. Se entrambe queste condizioni sono
vere, l'istruzione restituisce true, e ci ritroviamo con un'operazione OR:

if (true || BooleanVar1 == false)

Questa affermazione valuta automaticamente al vero, dal momento che una delle condizioni è già realtà. Ma cosa succede se

(BooleanVar1 == true && Indicator1> Indicator2) è falsa?

if (falsa || BooleanVar1 == false)

Se la condizione BooleanVar1 == false restituisce true, allora l'intero affermazione è vera. (In altre parole, se BooleanVar1 è
impostato per falso, tale condizione restituisce true.) In caso contrario, l'affermazione è falsa.

E 'possibile creare operazioni booleane complesse utilizzando AND, OR e parentesi per controllare l'ordine delle operazioni. Essere sicuri
di vedere le posizioni dei vostri parentesi, come una parentesi sbagliata può causare la dichiarazione di valutare in modo diverso, e una
parentesi mancante potrebbe portare a qualche debug noioso.

Trasformando un indicatore e spegnimento

È possibile utilizzare l'E / O esempio nella sezione precedente per trasformare un indicatore di on e off. Diciamo che il tuo EA utilizza più indicatori, e vi

piacerebbe essere in grado di passare gli indicatori on e off. Ecco come lo facciamo. In primo luogo, cerchiamo di dichiarare una variabile booleana

esterna da utilizzare come l'interruttore on / off. Useremo l'indicatore stocastico in questo esempio:

extern bool UseStochastic = true;

Si definiscono due serie di condizioni per il nostro indicatore - una "a" Stato e uno stato di "off". Stato ON consiste della variabile on / off sia

impostato su vero, insieme alla condizione di apertura ordine. Stato off consiste semplicemente nello / off variabile su essere impostato su

false.

if ((UseStochastic == true && Kline> LINEAD) || UseStochastic == false)


{// Acquistare ordine}

106
Ordine Condizioni e indicatori

La dichiarazione ( UseStochastic == true && Kline> LINEAD) è il nostro stato "on". Se la


UseStochastic variabile esterna è impostata vero, e la condizione di trading Kline> LINEAD restituisce vero, allora la condizione

dell'ordine stocastico sarà vera.

UseStochastic == false è il nostro stato "off". Se la UseStochastic variabile esterna è impostata su false, allora ( UseStochastic ==

true && Kline> LINEAD) FALSE, mentre UseStochastic == false valuta true.

Dal momento che l'on e off membri sono legati da un operatore o, solo uno di loro deve essere vero per rendere l'intera affermazione
è vera. Quindi, fintanto che sia a) l'indicatore è acceso, e la condizione dell'ordine è valido.; . Oppure b) la spia è spenta; l'intera
istruzione sarà vero, e le eventuali condizioni di ordine rimanenti possono essere valutati.

Aggiungiamo una seconda condizione commercio nostra condizione stocastica - la croce media mobile:

if (((UseStochastic == true && Kline> LINEAD) || UseStochastic == false)


&& FastMA> SlowMA)

In questo esempio, abbiamo aggiunto la condizione croce media mobile, FastMA> SlowMA. Si noti che abbiamo aggiunto un altro
insieme di parentesi per la condizione stocastica, dal momento che l'intera istruzione tra parentesi deve essere valutata prima.

In primo luogo, si valuta l'istruzione all'interno del più interne di parentesi: ( UseStochastic == true && Kline> LINEAD). Se la UseStochastic
parametro è impostato su vero, e Kline> LINEAD restituisce vero, la prima parte della dichiarazione è vero.

if ((vero || UseStochastic == false) && FastMA> SlowMA)

La condizione UseStochastic == false restituisce falsa. Ci rimane un'operazione OR, e poiché una delle condizioni è già vero,
l'intera condizione stocastico restituisce vero:

if ((true || false) && FastMA> SlowMA)

if (true && FastMA> SlowMA)

Se FastMA> SlowMA restituisce vero, l'intera condizione di trading è vero, e l'ordine è collocato. Se è falsa, l'istruzione restituisce falso,
e l'ordine non viene inserito.

Ora, che cosa succede se la condizione stocastico trading è falsa? Se UseStochastic è impostato su true, e
Kline> LINEAD è falsa, l'intera condizione diventa falsa:

107
E XPERT UN dvisor P ROGRAMMAZIONE

if ((|| UseStochastic falso == false) && FastMA> SlowMA)

if ((false || false) && FastMA> SlowMA)

se (false && FastMA> SlowMA)

Indipendentemente da come FastMA> SlowMA valuta, l'intera condizione commerciale è falsa.

Ora diciamo che UseStochastic è impostato su false. In questo caso, la dichiarazione ( UseStochastic == true && Kline>
LINEAD) restituisce false:

if ((|| UseStochastic falso == false) && FastMA> SlowMA)

Dal momento che la dichiarazione UseStochastic == false È vero, la condizione stocastico restituisce true.

if ((false || vero) && FastMA> SlowMA)

if (true && FastMA> SlowMA)

Il che significa che se FastMA> SlowMA valuta anche vero, l'ordine verrà collocato. In questo caso, la condizione stocastico
non ha neppure costituito, oltre a valutare lo stato on / off dell'indicatore.

Confrontando i valori degli indicatori Across Bar

A volte è necessario confrontare il valore dell'indicatore della barra corrente o più recentemente chiusa per il valore dell'indicatore di una barra

precedente. Per esempio, diciamo che si desidera sapere se una media mobile sta andando verso l'alto o verso il basso. Per fare questo, mettiamo a

confronto la lettura dell'indicatore della barra corrente a quello della barra precedente.

Noi usiamo il Cambio parametro di una funzione di indicatore per determinare quali bar, restituendo il valore indicatore. Il Cambio parametro
è sempre l'ultimo parametro in una funzione indicatore. Barra corrente ha uno spostamento di 0, la barra precedente ha uno
spostamento di 1, e così via. Le funzioni media mobile sotto restituirà un valore di media mobile per la corrente e la barra precedente:

Doppio MA = iMA (NULL, 0, MAPeriod, 0, MAMethod, MACOSTI, 0);


Doppio LASTMA = iMA (NULL, 0, MAPeriod, 0, MAMethod, MACOSTI, 1);

108
Ordine Condizioni e indicatori

In questo esempio, MA è la variabile che contiene il valore dell'indicatore della barra corrente, mentre LASTMA detiene valore dell'indicatore della barra

precedente. Si noti che il Cambio parametro è 0 per la barra corrente, e 1 per la misura precedente.

Ecco il codice per determinare se una linea di media mobile si sta muovendo verso l'alto o verso il basso:

if (MA> LASTMA)
{// MA sta salendo}

else if (MA <LASTMA)


{// MA sta andando giù}

Se il valore dell'indicatore della barra corrente ( MA) è maggiore del valore della barra precedente ( LASTMA),
possiamo concludere che l'indicatore si sta muovendo. L'inverso è vero quando il valore dell'indicatore della barra attuale è inferiore al valore

dell'indicatore della barra precedente.

Confrontando il valore dell'indicatore di una barra precedente a quello attuale, possiamo determinare se l'indicatore ha recentemente
attraversato sopra o al di sotto di un certo valore, tale le ipercomprato / ipervenduto livelli di un oscillatore, o un'altra linea indicatore.

Per esempio, supponiamo che il tuo sistema di trading dà un segnale di mestiere, quando lo stocastico passa al di sopra o al di sotto di 30 70. Ecco il

codice per verificare che:

doppia Stoch = iStochastic (NULL, 0, KPeriod, DPeriod, rallentando, MAMethod, Prezzo, 0, 0);
doppia LastStoch = iStochastic (NULL, 0, KPeriod, DPeriod, rallentando, MAMethod, Prezzo, 0, 1);

if (Stoch> 30 && LastStoch <30)


{// aperto buy ordine}

if (Stoch <70 && LastStoch> 70)


{// ordine aperto vendita}

Stoch è il valore dell'indicatore della barra corrente, mentre LastStoch è il valore dell'indicatore della barra precedente. Se Stoch è

maggiore di 30 e LastStoch è inferiore a 30, si può concludere che l'indicatore ha attraversato sopra del livello ipervenduto entro l'ultima
barra. Invertendo le operatori di confronto, si può verificare una recente cross di sotto di un valore costante, come il livello di
ipercomprato 70.

109
E XPERT UN dvisor P ROGRAMMAZIONE

Ecco un altro esempio usando le medie mobili. Creeremo una condizione per aprire un ordine solo quando il FastMA e il SlowMA hanno
attraversato nell'ultimo bar:

doppio FastMA = iMA (NULL, 0, FastMAPeriod, 0,0,0,0); doppio SlowMA = iMA


(NULL, 0, SlowMAPeriod, 0,0,0,0);

doppio LastFastMA = iMA (NULL, 0, FastMAPeriod, 0,0,0,1); doppio LastSlowMA =


iMA (NULL, 0, SlowMAPeriod, 0,0,0,1);

if (FastMA> SlowMA && LastFastMA <= LastSlowMA


&& BuyMarketCount (Simbolo (), MagicNumber) == 0)
{// aperto buy ordine}

if (FastMA <SlowMA && LastFastMA> = LastSlowMA


&& SellMarketCount (Simbolo (), MagicNumber) == 0)
{// ordine aperto vendita}

In questo esempio, stiamo confrontando il rapporto di due indicatori a vicenda. LastFastMA e


LastSlowMA restituire i valori medi in movimento per la barra precedente. Se LastFastMA è inferiore (o uguale a) LastSlowMA, e FastMA è

attualmente superiore SlowMA, allora sappiamo che la linea di media in rapido movimento ha attraversato al di sopra della linea di media

lenta che si spostano all'interno l'ultima barra.

Ciò fornisce un segnale di trading affidabile, dal momento che possiamo limitare la nostra dell'ordine a destra dopo il verificarsi della croce. È

possibile modificare il Cambio valore per il LastFastMA e LastSlowMA funzioni, se si desidera aumentare il numero di barre di guardare indietro

quando trovare un indicatore croce.

Abbiamo aggiunto la LastFastMA e LastSlowMA rispetto ai nostri buy e ordine di vendita condizioni nel nostro consulente esperto. Possiamo ora

rimuovere il Comprare un biglietto e SellTicket verificare, dal momento che questo metodo è più affidabile, che il controllo di un numero di ticket ordine

memorizzato. Inoltre, non si deve preoccupare gli ordini di essere immessi anche dopo il verificarsi della croce. Vedere il codice di consulente esperto

in Appendice C per visualizzare tutte le modifiche.

110
Ordine Condizioni e indicatori

111
E XPERT UN dvisor P ROGRAMMAZIONE

Capitolo 7
Lavorare con ora e data

Variabili datetime

Internamente, la appuntamento variabile è rappresentato come il numero di secondi trascorsi dal 1 ° gennaio
1970. Per esempio, 15 giugno 2009 alle 0:00 (mezzanotte) sarebbe 1245024000. Il vantaggio del formato datetime è che
rende i confronti temporali passate e future e manipolazioni matematiche molto facile.

Ad esempio, se si voleva verificare se una data viene prima o dopo un'altra data, si dovrebbe fare una semplice
operazione relazionale. Diciamo che Data d'inizio è il 15 giugno 2009 alle 14:00 e
Data di fine è il 16 giugno 2009 alle 05:00.

if (StartDate <DataFine) // risultato è true se (StartDate> DataFine) //


risultato è falso

Un altro vantaggio è che è possibile aggiungere o sottrarre tempo da una data particolare, semplicemente aggiungendo o sottraendo il numero

appropriato di secondi. Se si desidera aggiungere 24 ore per Data d'inizio, è sufficiente aggiungere il numero di secondi in un giorno:

datetime AddDay = StartDate + 86400;

Se hai intenzione di fare un sacco di manipolazione matematica con le variabili datetime, potrebbe essere una buona idea per dichiarare

alcune costanti intere per rappresentare alcune unità di tempo:

# definire SEC_H1 3600 // secondi in un'ora


# definire SEC_D1 86400 // secondi in un giorno

Lo svantaggio di appuntamento formato è che non è molto leggibile. Non si può guardare ad un valore tale da 1.245.024 mila e dire

automaticamente che essa rappresenta 15 GIUGNO 2009 alle 0:00. Per questo, usiamo funzioni di conversione per convertire datetime da e

verso una forma più leggibile.

datetime Costanti

Una costante datetime è una data e l'ora presentato nel seguente formato stringa: yyyy.MM.dd hh: mm.
Ad esempio, 15 giugno 2009 alle 0:00 sarebbe 2009.06.15 00:00. Ci sono altri accettabili

112
Lavorare con ora e data

formati per le costanti datetime: il tema di riferimento MQL Nozioni di base - Tipi di dati - le costanti Datetime
ha più informazioni. Useremo il formato presentato in precedenza, dal momento che è l'unico che può essere facilmente convertito.

Per convertire una variabile datetime ad una costante stringa, utilizzare la funzione TimeToStr (). Ecco la sintassi:

stringa TimeToStr (datetime Tempo, int uscita = TIME_DATE | TIME_MINUTES);

• Tempo - Una variabile datetime espressa come numero di secondi trascorsi dal 1 ° gennaio,
1970.

• Produzione - Un parametro facoltativo che emette la costante come unica data, l'ora e solo minuto; ore, minuti e
secondi; o qualsiasi combinazione di data e ora. valori di input validi sono:

◦ ORA DELL'APPUNTAMENTO - Emette la data, ad esempio, 2009.06.15

◦ TIME_MINUTES - Uscite ora e minuto, per esempio, 05:30

◦ TIME_SECONDS - Uscite ora, minuti e secondi, per esempio, 05:30:45

All'uscita la stringa costante nella predefinito YYYY.MM.DD hh: mm formato, lasciare Produzione vuoto. Se si desidera solo la
data o l'ora ei minuti (o secondi), utilizzare l'argomento appropriato. In questo esempio, si suppone che Orario di inizio è uguale
a 2009.06.15 05:30:45.

TimeToStr (StartTime, TIME_DATE) // Returns "2009.06.15"


TimeToStr (StartTime, TIME_SECONDS) // Returns "05:30:45"
TimeToStr (StartTime, TIME_MINUTES) // Returns "05:30"
TimeToStr (StartTime, TIME_DATE | TIME_SECONDS) // restituisce "2009.06.15 05:30:45" TimeToStr (StartTime)
// Restituisce "2009.06.15 05:30"

Possiamo costruire una costante datetime mediante concatenazione di stringhe e convertirlo in una variabile datetime utilizzando la
funzione Strtotime (). La sintassi è identica a TimeToStr () sopra, ma senza la Produzione parametro. La costante stringa deve essere nel
formato YYYY.MM.DD hh: mm da convertire in modo corretto.

Ecco un esempio di come si possa assemblare un costante datetime utilizzando numeri interi, convertire i numeri interi in formato stringa e

convertire la stringa in una variabile datetime. In primo luogo, la dichiareremo alcune variabili esterne per impostare una data e l'ora:

extern int UseMonth = 6; extern int UseDay


= 15; extern int UseHour = 5; extern int
UseMinute = 30;

113
E XPERT UN dvisor P ROGRAMMAZIONE

Successivamente, creiamo la costante stringa usando il StringConcatenate () funzione, e infine convertire la stringa appuntamento formato
utilizzando Strtotime ().

stringa DateConstant = StringConcatenate (Anno (), "", UseMonth, "", UseDay,"",


UseHour, ":", UseMinute); // DateConstant è "2009/06/15 05:30"

datetime StartTime = strtotime (DateConstant); // StartTime è "1245,0438 milioni"

Si noti che nel StringConcatenate () la funzione, usiamo Anno() restituire l'anno corrente invece di utilizzare una variabile esterna. È
possibile utilizzare funzioni come Mese giorno() e così via per inserire i valori correnti di tempo. Parleremo questi nella prossima sezione.

Data e ora

Ci sono due funzioni che restituiscono il tempo corrente: TimeCurrent () restituisce il tempo corrente del server, mentre TimeLocal () restituisce
il tempo del computer locale. È possibile utilizzare se si preferisce. Si consiglia di creare una variabile booleana esterna per scegliere
tra i due:

extern bool UseLocalTime = true;

Ecco il codice per assegnare sia l'ora locale corrente o l'ora del server corrente a una variabile denominata
Ora attuale.

if (UseLocalTime == true) datetime = CurrentTime TimeLocal (); // Ora locale


altro CurrentTime = TimeCurrent (); // Orario del server

A volte si può solo bisogno di recuperare una parte del tempo corrente, come ad esempio l'ora o giorno. Ecco l'elenco delle funzioni più utili è

possibile utilizzare per restituire i valori di tempo corrente. Tutte queste funzioni utilizzare il tempo del server - non è il tuo tempo di computer

locale. Il valore di ritorno è di tipo intero:

• Anno() - L'anno a quattro cifre attuale, ad esempio 2009.

• Mese() - La corrente mese dell'anno 1-12.

• Giorno() - L'attuale giorno del mese da 1 a 31.

• Giorno della settimana() - Un numero intero che rappresenta il giorno corrente della settimana. Domenica è 0, Lunedi è

1, Venerdì è 5 e così via.

• Ora() - L'ora corrente nel tempo di 24 ore, da 0 a 23. Ad esempio, 03:00 è 3, ed è 15:00

15.

• Minute () - Il minuto corrente da 0 a 59.

114
Lavorare con ora e data

È inoltre possibile recuperare questi valori da qualsiasi variabile datetime utilizzando un diverso insieme di funzioni. Queste funzioni

richiedono una variabile datetime come unico parametro, ma altrimenti funzionano come le suddette funzioni. Se si desidera recuperare un

valore di tempo da TimeLocal (), utilizzare l'uscita del

TimeLocal () funzione come argomento per le seguenti funzioni:

• TimeYear () - L'anno a quattro cifre del valore datetime specificato.

• TimeMonth () - Il mese del valore datetime specificato da 1 a 12.

• TimeDay () - Il giorno del mese del valore datetime specificato da 1 a 31.

• TimeDayOfWeek () - Un numero intero che rappresenta il giorno della settimana del valore datetime specificato. Domenica è 0,

è Lunedi 1, Venerdì è 5 e così via.

• TimeHour () - L'ora del valore datetime specificato nel tempo di 24 ore, da 0 a 23.

• TimeMinute () - La minuto del valore datetime specificato da 0 a 59.

Ecco alcuni esempi di utilizzo di queste funzioni. Supponiamo che TimeLocal () è uguale a
2009.06.15 05:30.

datetime CurrentTime = TimeLocal ();

int = GetMonth TimeMonth (OraCorrente); // Returns 6


int = GetHour TimeHour (OraCorrente); // Returns 5
int = GetWeekday TimeDayOfWeek (OraCorrente); // Restituisce 1 per Lunedi

Creazione di un timer semplice

Una cosa molto utile che possiamo fare con il tempo e la data in MQL è quello di aggiungere un timer per il nostro consulente esperto. Alcuni

operatori, come per limitare il loro trading per le ore più attivi del giorno, come le sessioni di Londra e New York. Altri potrebbero voler evitare di

trading durante gli eventi di mercato volatile, quali i rapporti di notizie e NFP.

Per costruire un timer, è necessario specificare un orario di inizio e di fine. Useremo variabili intere esterne per inserire i parametri
temporali. Creeremo una costante di stringa datetime, e convertire che a una variabile datetime. Ci sarà quindi confrontare i nostri
tempi di inizio e fine al tempo corrente. Se l'ora corrente è maggiore del tempo di avvio, ma meno del tempo della fine, il commercio
sarà consentito.

Qui ci sono le variabili esterne che andremo ad utilizzare. Ci impostare una variabile per accendere il timer on e off, così come per selezionare

l'ora corrente (server o locale). Abbiamo mese, giorno, ora e minuti impostazioni per entrambi i tempi di inizio e di fine:

115
E XPERT UN dvisor P ROGRAMMAZIONE

extern bool UseTimer = true; extern bool UseLocalTime


= false;

extern int StartMonth = 6; extern int StartDay


= 15; extern int StartHour = 7; extern int
StartMinute = 0;

extern int EndMonth = 6; extern int EndDay


= 15; extern int endHour = 2; extern int
EndMinute = 30;

E qui è il codice per controllare se consentire o meno il commercio. la variabile TradeAllowed


determina se aprire nuovi scambi. Se UseTimer è impostato su false, TradeAllowed viene automaticamente impostata su true. In caso contrario,

valutiamo i nostri tempi di inizio e fine in relazione al tempo corrente per vedere se ci permetteremo di trading o no.

if (UseTimer == true)
{// Convertire ora di inizio

stringa StartConstant = StringConcatenate (Anno (), "", StartMonth, "", StartDay,"",


StartHour, ":", StartMinute);

datetime StartTime = strtotime (StartConstant);

if (StartMonth == 12 && StartDay == 31 && EndMonth == 1) int EndYear = Anno () + 1; altro EndYear = Anno ();

// Convertire ora di fine


stringa EndConstant = StringConcatenate (EndYear, "", EndMonth, "", EndDay,"",
EndHour, ":", EndMinute);

datetime EndTime = strtotime (EndConstant);

// Scegli ora locale o del server


if (UseLocalTime == true) datetime = CurrentTime TimeLocal (); altro CurrentTime = TimeCurrent ();

// Verificare la presenza di condizioni di commercio

if (StartTime <= CurrentTime && EndTime> OraCorrente)


{Bool TradeAllowed = true; }

altro TradeAllowed = false; }

altro TradeAllowed = true;

116
Lavorare con ora e data

Iniziamo convertendo il nostro tempo di avvio a una variabile datetime, Orario di inizio. La dichiarazione

if (StartMonth == 12 && StartDay == 31 && EndMonth == 1) controlla se la data di inizio è l'ultimo giorno dell'anno, e se il giorno

finale è dopo la prima del prossimo anno. Se è così, si incrementa automaticamente la fine anno di 1. In caso contrario, si usa
l'anno in corso per EndYear.

Avanti, convertiamo il tempo finale alla variabile datetime Fine del tempo e scegliere quale Ora attuale vogliamo usare, server o locale.
Il finale Se controlli di blocco per vedere se l'ora attuale è tra i tempi di inizio e di fine. Se è così, TradeAllowed è impostata su true.

Ora abbiamo bisogno di aggiungere il codice per controllare l'esecuzione del commercio. Il modo più semplice per farlo è quello di aggiungere un Se

bloccare intorno la nostra routine di apertura ordine:

// Inizia blocco commerciale se


(TradeAllowed == true)
{// Acquista Order

if (FastMA> SlowMA && BuyTicket == 0 && BuyOrderCount (Simbolo (), MagicNumber) == 0)


{// Acquistare codice d'ordine omesse per brevità}

// Sell Order
if (FastMA <SlowMA && SellTicket == 0 && SellOrderCount (Simbolo (), MagicNumber) == 0)
{// codice di vendita ordine omesse per brevità}

} // Fine blocco commerciale

Ci sono molti altri modi per creare timer - per esempio, è possibile utilizzare il giorno della settimana invece del mese e giorno, o gli orari
commerciali impostato rispetto al giorno corrente. Lasceremo a voi, il lettore, per creare un timer che è appropriato per le vostre
esigenze.

Eseguire su Bar Aperto

Per impostazione predefinita, consulenti esperti eseguiti in tempo reale, su ogni tick. Ma in alcuni casi, può essere meglio controllare le condizioni

degli scambi solo una volta per bar. Aspettando barra corrente per chiudere, possiamo essere sicuri che si è verificata la condizione e che il

segnale è valido. In confronto, mediante l'esecuzione di mestieri in tempo reale, potremmo essere più suscettibili a falsi segnali.

Trading una volta per misura significa anche che i risultati nel Tester strategia saranno più accurate e pertinenti. A causa dei limiti intrinseci
della Strategia Tester di MetaTrader, utilizzando "ogni tick", come il modello di test sarà produrre risultati di back testing inaffidabili, a causa
del fatto che le zecche sono spesso modellate

117
E XPERT UN dvisor P ROGRAMMAZIONE

dai dati M1. I mestieri che si verificano in trading dal vivo non corrispondono necessariamente agli scambi fatta nel Tester strategia.

Ma mettendo i nostri commerci sulla stretta sulla barra e l'utilizzo di "prezzi Aperto solo", come il modello di prova, siamo in grado di ottenere risultati

di test che riflettono più accuratamente i commerci in tempo reale. Lo svantaggio di negoziazione una volta per misura è che i commerci possono

essere eseguiti in ritardo, soprattutto se c'è un sacco di movimento dei prezzi nel corso del bar. E 'fondamentalmente un compromesso tra reattività

e affidabilità.

Per controllare le condizioni degli scambi una volta per misura, dobbiamo esaminare il timestamp della barra corrente. Salveremo questo

timestamp a una variabile globale. Su ogni esecuzione del consulente esperto, avremo confrontare il timestamp salvato alla corrente

timestamp. Una volta che il timestamp degli attuali cambiamenti bar, che indica che un nuovo bar ha aperto, ci sarà quindi controllare le

condizioni di negoziazione.

Dobbiamo anche regolare il parametro di spostamento delle nostre funzioni indicatori, funzioni di prezzo e matrici per restituire il valore della barra

precedente. Se un array funzione indicatore o prezzo viene stabilito controlla la barra corrente, noi spostare l'indice barra da 1 controlla la barra

precedente invece. Tutti gli indicatori e gli array di prezzo devono avere i parametri di spostamento incrementato di 1.

Tecnicamente, stiamo verificando le condizioni degli scambi al primo segno di spunta di una nuova barra, mentre esaminando il valore della barra precedente

chiusura. Non si controlla la barra attualmente aperto durante l'esecuzione di una volta al bar.

Ecco il codice per controllare l'apertura di un nuovo bar. In primo luogo, si dichiara una variabile esterna di nome

CheckOncePerBar per attivare questa funzione e si spegne. Poi dichiariamo un appuntamento variabile globale per memorizzare il timestamp della

barra corrente - questo sarà IndicatoreDataOraCorrente.

Nel dentro() funzione, viene assegnato il timestamp della barra corrente IndicatoreDataOraCorrente. Questo ritarderà il controllo di condizione di

commercio fino all'apertura della barra seguente:

// Le variabili esterne
extern bool CheckOncePerBar = true;

// Le variabili globali datetime


IndicatoreDataOraCorrente;

// Init funzione int init ()

{IndicatoreDataOraCorrente = Tempo [0]; }

118
Lavorare con ora e data

Ecco il codice che va all'inizio del nostro inizio() la funzione, subito dopo il timer. La variabile intera BarShift determinerà se impostare la Cambio
il valore delle nostre funzioni degli indicatori e dei prezzi alla barra corrente o della barra precedente. La variabile booleana NewBar determinerà
se si provvederà a controllare le nostre condizioni commerciali:

if (CheckOncePerBar == true)
{Int BarShift = 1;

if (IndicatoreDataOraCorrente! = Tempo [0])


{IndicatoreDataOraCorrente = Tempo [0];

bool NewBar = true; }

altro NewBar = false; } altro

{NewBar = true;

BarShift = 0; }

Se CheckOncePerBar è impostato per vero, per prima cosa impostare BarShift a 1. Questo imposterà il Cambio parametro di tutte le funzioni dell'indicatore

e prezzo / array alla barra precedente.

Successivamente, si confronta il valore di IndicatoreDataOraCorrente variabile Time [0], che è il timestamp della barra corrente. Se i due
valori non corrispondono, viene assegnato il valore di Time [0] a
IndicatoreDataOraCorrente e impostare NewBar su true. Le condizioni del mercato saranno controllati poco dopo.

Alle esecuzioni successive, IndicatoreDataOraCorrente e Time [0] corrisponderà, il che significa che NewBar sarà impostato su false. Le condizioni commerciali

non saranno controllati fino a quando un nuovo bar si apre. Una volta che un nuovo bar si apre,

Time [0] sarà un valore diverso IndicatoreDataOraCorrente, e NewBar sarà impostato su true, ancora una volta.

Se CheckOncePerBar è impostato per falso, NewBar sarà automaticamente impostato su vero, e BarShift sarà impostato 0. Questo controllerà le

condizioni di trading su ogni tick, come prima.

Il BarShift variabile dovrà essere assegnato alla Cambio parametro di eventuali funzioni indicatrici, funzioni di prezzo o le matrici che
fanno riferimento la barra più recente. Ecco alcuni esempi di come questo sarebbe stata applicata:

doppio FastMA = iMA (NULL, 0, FastMAPeriod, 0,0,0, BarShift);

if (Chiudi [ BarShift] > Aperto[ BarShift])

doppio UseLow = ILOW (NULL, 0, BarShift);

119
E XPERT UN dvisor P ROGRAMMAZIONE

Si dovrebbe riconoscere questi esempi da prima. Invece di controllare la barra corrente, si provvederà a controllare il bar che appena chiuso, vale a dire la

barra precedente. Se avete bisogno di fare riferimento a un barra precedente per l'ultima barra chiusa, è sufficiente aggiungere il parametro spostamento

corrente BarShift:

doppio LastFastMA = iMA (NULL, 0, FastMAPeriod, 0,0,0, BarShift + 1);

Se non anticipare mai dover eseguire il consulente esperto una volta per misura, non sarà necessario aggiungere questo codice. Ma per molti

sistemi di trading basate su indicatori, questo può fare il tuo trading e posteriore risultati dei test più affidabile.

Per controllare l'esecuzione degli scambi, occorre controllare il valore di NewBar prima che le routine dell'ordine. Possiamo farlo utilizzando il Se

bloccare abbiamo messo in precedenza per il timer:

// Inizia blocco commerciale se (TradeAllowed == true && NewBar ==


true)
{// Acquistare Ordinare

if (FastMA> SlowMA && BuyTicket == 0 && BuyOrderCount (Simbolo (), MagicNumber) == 0)


{// Acquistare codice d'ordine omesse per brevità}

// Sell Order
if (FastMA <SlowMA && SellTicket == 0 && SellOrderCount (Simbolo (), MagicNumber) == 0)
{// codice di vendita ordine omesse per brevità}

} // Fine blocco commerciale

120
Lavorare con ora e data

121
E XPERT UN dvisor P ROGRAMMAZIONE

Capitolo 8
Suggerimenti e trucchi

In questo capitolo, ci occuperemo funzionalità aggiuntive che possono essere utili nei vostri consulenti esperti.

caratteri di escape

Se si desidera aggiungere citazioni o un carattere di backslash in una stringa costante, è necessario fuga il carattere utilizzando una barra

rovesciata (\). Ad esempio, se è necessario inserire una doppia citazione, il carattere di escape sarà \" Per una singola citazione, il carattere

di escape è \' Per un backslash, utilizzare due barre rovesciate come il carattere di escape:.. \\

EscQuotes String = "Questa stringa ha \" scappati doppi apici \ ""; // output: Questa stringa è "sfuggito
virgolette doppie"

stringa EscQuote = "Questa stringa è \ 'sfuggito apici \'"; // Output: Questa stringa è 'sfuggito virgolette
singole'

stringa EscSlash = "Questa stringa ha una barra rovesciata sfuggito \\"; // Output: Questa stringa ha
una barra rovesciata sfuggito \

Se avete bisogno di una stringa per estendersi su più righe, utilizzare il carattere di escape \ n per aggiungere una nuova riga:

stringa NewLine = "Questa stringa è \ na nuova linea"; // Output: Questa stringa


ha
una nuova riga

Utilizzando Grafico Commenti

È possibile stampare il testo in alto a sinistra del grafico utilizzando il Commento() funzione. Questo può essere utilizzato per stampare le informazioni di

stato, le impostazioni degli indicatori o qualsiasi altra informazione si possono trovare utili.

Un metodo per la visualizzazione dei commenti grafico è quello di dichiarare diverse variabili stringa e concatenare insieme a caratteri di nuova

riga. Una stringa può essere utilizzata per visualizzare le impostazioni, un altro per visualizzare i messaggi di informazione o stato degli ordini,

ecc La stringa concatenata sarà passato al Commento()

funzione. Posiziona il Commento() funzione alla fine del inizio() funzione per aggiornare la tabella di commento:

122
Suggerimenti e trucchi

stringa SettingsComment = "FastMAPeriod: "+ FastMAPeriod +" SlowMAPeriod:" + SlowMAPeriod; stringa StatusComment = "Buy ordine
effettuato";

Commento (SettingsComment + "\ n" + StatusComment);

Dichiariamo e impostare i valori della SettingsComment


e StatusComment stringhe all'interno del inizio()
funzione. Alla fine della funzione di avvio, che noi chiamiamo il

Commento() funzionare e utilizzarla per stampare i nostri commenti al grafico.

Usiamo un carattere di nuova riga (\ n) per separare i commenti in due linee.

Fig 8.1: commento grafico utilizzando un carattere di nuova riga

Controllare le impostazioni

Ci sono diverse proprietà consulente esperto che deve essere attivo prima che il consulente esperto può essere consentito al commercio.

Queste impostazioni si trovano sotto la Comune linguetta nel Proprietà Expert dialogo.

Le impostazioni Consenti live trading deve essere attivato prima di trading può iniziare. Se non è abilitato, un volto accigliato apparirà
in alto a destra del grafico, accanto al nome del consulente esperto. È possibile verificare questa condizione nel vostro EA utilizzando
il IsTradeAllowed () funzione. Se restituisce false, l'impostazione Consenti live trading è disabilitato.

Se si desidera visualizzare un messaggio all'utente indicando che questa impostazione deve essere attivata, si può fare come segue:

if (IsTradeAllowed () == false) alert ( "attivare l'impostazione \ 'Consenti dal vivo di trading \' nel
Proprietà Expert! ");

Se il consulente esperto utilizza un esterno. ex4 biblioteca, l'impostazione Consentire l'importazione di esperti esterni deve essere abilitato nel

Proprietà Expert. È possibile controllare questo utilizzando il IsLibrariesAllowed ()

funzione:

if (IsLibrariesAllowed () == false) alert ( "attivare l'impostazione \ 'Consenti importazione di esterni


esperti \' nella proprietà di esperti! ");

La stessa cosa può essere fatto per le DLL utilizzando il IsDllsAllowed () funzione:

if (IsDllsAllowed () == false) alert ( "attivare l'impostazione \ 'Consenti importazioni DLL \' nel
Proprietà Expert! ");

123
E XPERT UN dvisor P ROGRAMMAZIONE

Fig. 8.2 - scheda Comune di dialogo Expert Advisor Proprietà.

È possibile visualizzare tutte le funzioni del terminale checkup in riferimento MQL sotto Verifica.

Demo o conto dei limiti

Si può decidere a un certo punto di vendere il vostro consulente esperto redditizio per altri operatori. Si consiglia inoltre di fornire una versione

demo per i potenziali acquirenti di testare. Per evitare che il tuo EA di essere liberamente distribuito o negoziati da parte di persone non

autorizzate, ti consigliamo di inserire una sorta di limitazioni conto che limitano l'utilizzo di EA per gli acquirenti autorizzati. Si potrebbe anche

voler limitare l'uso di un particolare broker.

Per limitare l'utilizzo di un account demo, utilizzare il IsDemo () funzione per controllare se l'account attualmente attivo è un account
demo. Se il conto corrente non è un conto demo, ci mostrerà un avviso e fermare l'esecuzione della EA.

if (IsDemo () == false)
{Alert ( "Questo EA solo per l'uso su un conto demo!");

ritorno (0); }

124
Suggerimenti e trucchi

È possibile utilizzare le funzioni di account Nome utente(), AccountNumber () e AccountBroker () per controllare il nome dell'account,
numero e mediatore, rispettivamente. Limitare l'utilizzo dal numero di conto è un comune e facile da implementare il metodo di
protezione:

int CustomerAccount = 123456;

if (AccountNumber ()! = CustomerAccount)


{Alert ( "Numero di conto non corrisponde!");

ritorno (0); }

Puoi usare Nome utente() o AccountBroker () in modo simile. Per AccountBroker (), devi prima di usare un Stampare() dichiarazione
per recuperare il valore di ritorno corretta dal broker. Questo valore verrà stampato nel log gli esperti.

Se si decide di vendere un EA commercialmente, essere consapevoli del fatto che i file MQL sono notoriamente facili da decompilare. Ci sono vari

metodi che è possibile utilizzare per rendere più difficile per gli hacker di rompere la tua EA, come l'immissione funzioni nelle biblioteche o DLL

esterne. Ma in ultima analisi, v'è poca protezione contro un cracker determinata.

Casella dei messaggi()

Finora in questo libro, abbiamo usato il built-in Mettere in guardia() funzione per visualizzare i messaggi di errore. Ma cosa succede se si desidera personalizzare le

finestre di dialogo di avviso, o richiedere input da parte dell'utente? Il Casella dei messaggi()

funzione consente di creare una finestra personalizzata pop-up utilizzando le funzioni API di Windows.

Per utilizzare il Casella dei messaggi() la funzione, dobbiamo prima # includere il WinUser32.mqh file installato con MetaTrader. Questo file
importa funzioni da Windows user32.dll file e definisce le costanti necessarie per la Casella dei messaggi() la funzione di lavorare. Ecco la
sintassi per la Casella dei messaggi() funzione:

int MessageBox (string Testo, stringa Titolo, int Bandiere);

Per utilizzare il Casella dei messaggi() funzione, è necessario definire il Testo ad apparire nella finestra pop-up, insieme a un Titolo che appare nella barra

del titolo. Ci sarà inoltre necessario specificare bandiere che indicano quali pulsanti e le icone dovrebbero apparire nel nostro pop-up. Se non vengono

specificate le bandiere, un pulsante OK sarà il valore predefinito. Bandiere devono essere separati dal tubo di carattere | ().

Ecco un esempio di una finestra di messaggio con Yes / No pulsanti e un'icona a forma di punto interrogativo:

125
E XPERT UN dvisor P ROGRAMMAZIONE

// direttive del preprocessore


# includere <WinUser32.mqh>

// funzione di avvio ()
int YesNoBox = MessageBox ( "Mettere un commercio?", "Trade Conferma",
MB_YESNO | MB_ICONQUESTION);

if (YesNoBox == IDYES)
{ // Invia ordine }

La bandiera MB_YESNO specifica che useremo Sì / No pulsanti nella nostra

finestra di messaggio, mentre il MB_ICONQUESTION

Bandiera pone il punto di domanda nella finestra di dialogo. La variabile


intera YesNoBox detiene il valore di ritorno del
Casella dei messaggi() funzioni, che indica quale tasto è stato

premuto.

Se il pulsante è stato premuto Sì, il valore di YesNoBox


sarà IDYES, e un ordine verrà collocato. Se il pulsante è stato premuto No, la
Fig. 8.3 - finestra Popup creata usando l'MessageBox
bandiera di ritorno sarà COD. È possibile utilizzare il valore di ritorno di Casella
function ()
dei messaggi() come input per determinare una linea di azione, come un ordine.

Quello che segue è un elenco parziale di bandiere da utilizzare per le finestre di messaggio. Per un elenco completo, vedere l'argomento di riferimento

MQL Costanti standard - MessageBox.

Button Bandiere

Questi flag specificano quali pulsanti appaiono nella tua casella di messaggio.

• MB_OKCANCEL - OK e Annulla.

• MB_YESNO - Sì e No tasti.

• MB_YESNOCANCEL - Sì, No e Annulla.

126
Suggerimenti e trucchi

icona Bandiere

Questi flag specificano icone visualizzate accanto al testo nella finestra di messaggio.

• MB_ICONSTOP - L'icona di stop.

• MB_ICONQUESTION - L'icona punto interrogativo.

• MB_ICONEXCLAMATION - un punto esclamativo.

• MB_ICONINFORMATION - Un'icona informazioni.

Bandiere return

Questi flag sono il valore di ritorno della Casella dei messaggi() funzione, e il pulsante indica che è stato premuto.

• IDOK - Il pulsante OK è stato premuto.

• IDCANCEL - Il pulsante Annulla è stato premuto.

• IDYES - Il pulsante è stato premuto Sì

• IDNO - The No pulsante è stato premuto.

Avvisi e-mail

Il vostro consulente esperto può avvisare l'utente tramite email compravendite poste, potenziali configurazioni commerciali e altro ancora. La funzione Inviare una

mail() invierà una e-mail con l'oggetto e il corpo di vostra scelta per l'indirizzo di posta elettronica che è elencato nella Strumenti - Opzioni sotto la finestra di dialogo E-mail

scheda.

Nella scheda E-mail, è necessario innanzitutto specificare il server di posta SMTP con il numero di porta - ad esempio:

mail.yourdomain.com:25 - insieme a un nome utente e una password, se necessario. Verificare con il proprio ISP o provider di hosting per queste
informazioni.

È possibile utilizzare qualsiasi indirizzo di posta elettronica nel A partire dal campo. Il A campo è l'indirizzo di posta elettronica per inviare messaggi a. Assicuratevi di

controllare la Abilitare l'impostazione in alto per consentire l'invio di messaggi.

Il Inviare una mail() funzione ha due argomenti: il primo è l'oggetto del messaggio, e il secondo è il contenuto del messaggio
stesso. È possibile utilizzare nuove righe, caratteri di escape, variabili e costanti nel corpo dell'e-mail.

127
E XPERT UN dvisor P ROGRAMMAZIONE

Figura. 8.4 - Le impostazioni di posta elettronica sotto Strumenti - Opzioni.

Ecco un esempio di Inviare una mail() utilizzo:

stringa EmailSubject = "Buy ordine effettuato";


stringa EmailBody = "ordine di acquisto "+ biglietto +" posto sul "+ Simbolo () +" a" + Chiedi; // output del campione: "Compra
ordine 12584 immessi sul EURDUSD a 1,4544"

SendMail (EmailSubject, EmailBody);

Riprova in caso di errore

In questo libro, abbiamo cercato di verificare i parametri di ordine prima di tentare di effettuare un ordine, in modo da evitare messaggi di errore comuni a

causa di impostazioni errate o dei prezzi. Tuttavia, gli errori possono ancora verificarsi a causa di requotes, contesto commerciale problemi occupato o

server. Questi errori non possono sempre essere evitati, ma possiamo tentare di porre di nuovo l'ordine quando questo accade.

Per ritentare un ordine su un errore, ci metterà la OrderSend () funzione all'interno di un mentre ciclo continuo. Se

OrderSend () non restituisce un numero di biglietto, si ritenterà l'ordine di nuovo:

128
Suggerimenti e trucchi

int biglietteria = 0; while


(biglietteria <= 0)
{Biglietteria = OrderSend (Simbolo (), OP_BUY, Misura di lotto, OpenPrice, UseSlippage,

BuyStopLoss, BuyTakeProfit); }

Noi dichiariamo la variabile per il numero di biglietto prima, in questo caso Biglietto. Fintanto che Biglietto non è maggiore di 0, la mentre ciclo con la OrderSend

() la funzione verrà eseguito più e più volte. C'è un problema con questo circuito però. In caso di un errore di codifica o di qualche altro errore di

trading non corretto, il loop iterare a tempo indeterminato, e il vostro consulente esperto si bloccherà. Siamo in grado di alleviare questo con

l'aggiunta di un numero massimo di tentativi:

Tentativi int = 0; int


MaxRetries = 5;

int biglietteria = 0; while


(biglietteria <= 0)
{Biglietteria = OrderSend (Simbolo (), OP_BUY, Misura di lotto, OpenPrice, UseSlippage, BuyStopLoss,

BuyTakeProfit);
if (Tentativi <= MaxRetries) Retries ++; altro break;

Si dichiara una variabile da utilizzare come un contatore di tentativi ( Tentativi), e fissando un numero massimo di tentativi ( MaxRetries). Fino a

quando non abbiamo superato MaxRetries, il tentativi variabile viene incrementato e le un'iterazione nuovamente. Non appena MaxRetries viene

raggiunto, la rompere operatore termina il ciclo. Dopo questo, si può avvertire l'utente della condizione di errore, se necessario.

Se si vuole fare il ciclo di tentativo dipende da una particolare condizione di errore, possiamo controllare il codice di errore con una lista e restituire un

valore true se v'è una corrispondenza. Questa funzione contiene alcuni codici di errore comuni che indicano una condizione in cui un commercio

potrebbe essere ripetuta con successo:

bool ErrorCheck (int ErrorCode)


{Switch (ErrorCode)

{Case 128:
// timeout commerciale
tornare (true);

caso 136: // Off citazioni


tornare (true);

129
E XPERT UN dvisor P ROGRAMMAZIONE

caso 138: // requotes


tornare (true);

caso 146: // contesto commerciale occupato

tornare (true);

di default: ritorno (false);


}}

Questa funzione utilizza il interruttore operatore. Siamo alla ricerca di un Astuccio etichetta cui valore corrisponde all'espressione assegnato all'operatore

interruttore (in questo esempio, Codice di errore). Se un abbinamento Astuccio viene trovato, il codice dopo Astuccio viene eseguito. Se no Astuccio etichetta

corrisponde, quindi il codice dopo la predefinito

etichetta viene eseguito.

Quando un Astuccio partita viene trovato, il interruttore blocco deve essere terminato con un rompere o ritorno operatore. In questo esempio,

stiamo usando il ritorno per restituire un valore true / false torna alla funzione chiamante. Il interruttore operatore può essere utile per valutare una

corrispondenza per una costante intera, ma la sua utilità è piuttosto limitato.

Ecco come si usa ErrorCheck () per riprovare condizionalmente un posizionamento ordine:

int tentativi;
int MaxRetries = 5;

int biglietteria;
while (biglietteria <= 0)
{Biglietteria = OrderSend (Simbolo (), OP_BUY, Misura di lotto, OpenPrice, UseSlippage, BuyStopLoss,

BuyTakeProfit);

if (biglietteria == -1) int ErrCode = GetLastError ();


if (Tentativi <= MaxRetries && ErrorCheck (ErrCode) == true) Tentativi ++; altro break; }

Se la Biglietto ritorna - 1, che indica che si è verificato un errore, abbiamo recuperare il codice di errore utilizzando

GetLastError (). Passiamo il codice di errore al nostro ErrorCheck () funzionare sopra. Se il codice di errore corrisponde a qualsiasi degli

errori nella funzione di controllo degli errori, ErrorCheck () tornerà vero, e la


OrderSend () funzione verrà ripetuta fino a 5 volte.

130
Suggerimenti e trucchi

Utilizzando Order commenti come un identificatore

Abbiamo utilizzato il "numero magico" come identificatore ordine che identifica in modo univoco gli ordini come di essere immessi da un particolare

consulente esperto. Se il consulente esperto pone ordini multipli in una sola volta, e si vuole essere in grado di gestire ciascuno di questi ordini in modo

diverso, è possibile utilizzare il commento ordine come un identificatore opzionale.

Ad esempio, consente di dire la tua consulente esperto posizionerà due tipi di ordini. Si vuole essere in grado di modificare o chiudere questi

ordini separatamente. Ti consigliamo di utilizzare due OrderSend () funzioni e inserire un commento ordine diverso con ognuno. Poi, quando si

seleziona gli ordini utilizzando il ciclo ordine in capitolo

5, userete OrderComment () come una delle condizioni per la localizzazione ordini da modificare o chiudere.

stringa OrderComment1 = "primo ordine"; stringa


OrderComment2 = "secondo ordine";

// Predisporre un ordine
int Ticket1 = OrderSend (Simbolo (), OP_BUY, Misura di lotto, OpenPrice, UseSlippage, BuyStopLoss,
BuyTakeProfit, OrderComment1, MagicNumber, 0, verde);

int Ticket2 = OrderSend (Simbolo (), OP_BUY, Misura di lotto, OpenPrice, UseSlippage, BuyStopLoss,
BuyTakeProfit, OrderComment2, MagicNumber, 0, verde);

// modifica Order
for (int contatore = 0; contatore <= OrdersTotal () - 1; contatore ++)
{OrderSelect (Counter, SELECT_BY_POS);

if (OrderMagicNumber () == MagicNumber && OrderSymbol () == Simbolo ()


&& OrderComment () == OrderComment1)
{// Modificare primo ordine}

else if (OrderMagicNumber () == MagicNumber && OrderSymbol () == Simbolo ()


&& OrderComment () == OrderComment2)
{// Modificare secondo ordine}}

Noi dichiariamo due variabili stringa da usare come commenti dell'ordine. Il OrderSend () funzioni pongono due ordini, ciascuno con un

commento ordine diverso. La modifica ciclo esempio ordine che segue utilizza la OrderComment () funzionare come una condizione in cui si

seleziona ordini da modificare.

È possibile utilizzare il OrderComment () controllare per chiudere gli ordini indipendentemente da altri ordini, utilizzare diverse impostazioni di trailing stop, o

qualunque sia il vostro esigenze del sistema di trading.

131
E XPERT UN dvisor P ROGRAMMAZIONE

margine Controllare

MetaTrader è dotato di funzioni che consentono di controllare la corrente margine libero o stop out livello
prima di ordinare. Il livello di stop out è la percentuale o la quantità di margine libero di sotto del quale non sarà in grado di effettuare

ordini. Controllare manualmente il margine libero o interrompere il livello prima di ordinare non è realmente necessario tuttavia, come si

verificherà un errore se si tenta di effettuare un ordine con troppo poco margine.

Un'idea più utile sarebbe quello di determinare il proprio livello di stop out, e fermare il commercio, se il capitale corrente scende al di sotto di

tale livello. Cominciamo dichiarando una variabile esterna chiamata MinimumEquity,

che è la quantità minima di partecipazione richiesta sul nostro conto prima di poter effettuare un ordine.

Ci confrontiamo MinimumEquity sul nostro conto corrente del patrimonio netto. Se il capitale corrente è inferiore al nostro minima di
partecipazione, l'ordine non sarà posto, e un messaggio di avviso informerà l'utente della condizione. Supponiamo abbiamo un saldo
del conto di $ 10.000. Se perdiamo più del 20% di che l'equità, non vogliamo per effettuare l'ordine. Ecco il codice per controllare
l'equità minima:

// Le variabili esterne
extern int MinimumEquity = 8000;

// Predisporre un ordine
if (AccountEquity ()> MinimumEquity)
{ // Invia ordine }

else if (AccountEquity () <= MinimumEquity)


{Alert ( "equità corrente è inferiore minima di partecipazione dell'Ordine non messo!".); }

La variabile esterna MinimumEquity è posto all'inizio del file. Il resto del codice viene prima e dopo la funzione dell'ordine.
Se l'equità corrente, come indicato dal
AccountEquity (), è più grande di MinimumEquity, l'ordine verrà collocato. In caso contrario, l'ordine non sarà disposto e verrà

visualizzato un messaggio di avviso.

diffusione Controllare

Si potrebbe desiderare di evitare di mettere i commerci durante i periodi in cui la diffusione è allargato ben oltre il normale. Siamo in grado di

impostare uno spread massimo e verificare l'attuale diffusione prima di trading. Ci dichiariamo una variabile esterna chiamata MaximumSpread, e l'uso MarketInfo

() per controllare la diffusione corrente.

132
Suggerimenti e trucchi

Il codice sarà molto simile alla sezione precedente in cui abbiamo aggiunto il controllo minimo margine. Noi includere il codice della
sezione precedente per mostrare come questi vari controlli lavorano insieme:

// Le variabili esterne
extern int MaximumSpread = 5;
extern int MinimumEquity = 8000;

if (AccountEquity ()> MinimumEquity && MarketInfo (Simbolo (), MODE_SPREAD) <MaximumSpread)


{// Luogo ordine} else

{If (AccountEquity () <= MinimumEquity) alert ( "equità corrente è inferiore al minimo

equità! Ordine non collocato. ");

if (MarketInfo (Simbolo (), MODE_SPREAD)> MaximumSpread) alert ( "spread attuale è


maggiore di massima diffusione! Ordine non collocato. ");
}

Si noti che eseguiamo sia il controllo minimo l'equità e il controllo di diffusione prima di ordinare. Se un una delle condizioni
sono false, andiamo al altro blocco e controllare per vedere quale delle condizioni causato l'ordine di non essere collocato. Ci
mostrerà uno o più avvisi a seconda di quale condizione è vera.

ordini multipli

Si potrebbe desiderare di inserire più ordini al posizione con diversi stop loss e prendere livelli di profitto, così come i lotti. Ci sono diversi

modi per ottenere questo. Un modo è quello di utilizzare semplicemente un diverso

OrderSend () dichiarazione per ogni ordine che si desidera inserire. Ciò presuppone che si ha intenzione di collocare lo stesso numero di

ordini ogni volta.

Un altro modo è quello di utilizzare un per ciclo di inserire gli ordini. In questo modo, è possibile regolare il numero di ordini di mettere in una sola volta. È

possibile pre-caricare il tuo stop loss e prendere profitto prezzi in array, e incrementare attraverso le matrici del per ciclo continuo.

Cominciamo definendo variabili esterne per tre stop loss e prendere livelli di profitto. Eventuali ulteriori ordini superiori a tre non
avranno uno stop loss o take profit posto. Aggiungeremo anche una variabile esterna per regolare il numero di ordini a posto.

extern int StopLoss1 = 20; extern int


StopLoss2 = 40; extern int StopLoss3 = 60;

133
E XPERT UN dvisor P ROGRAMMAZIONE

extern int TakeProfit1 = 40; extern int TakeProfit2


= 80; extern int TakeProfit3 = 120;

extern MaxOrders int = 3;

Avanti, dichiareremo le nostre matrici, calcolare il nostro stop loss e take profit, e caricare i nostri prezzi calcolati nella matrice:

doppio BuyTakeProfit [3]; doppio


BuyStopLoss [3];

BuyTakeProfit [0] = CalcBuyTakeProfit (Simbolo (), TakeProfit1, Ask); BuyTakeProfit [1] =


CalcBuyTakeProfit (Simbolo (), TakeProfit2, Ask); BuyTakeProfit [2] = CalcBuyTakeProfit (Simbolo (),
TakeProfit3, Ask);

BuyStopLoss [0] = CalcBuyStopLoss (Simbolo (), StopLoss1, Ask); BuyStopLoss [1] =


CalcBuyStopLoss (Simbolo (), StopLoss2, Ask); BuyStopLoss [2] = CalcBuyStopLoss (Simbolo
(), StopLoss3, Ask);

Iniziamo dichiarando gli array per contenere lo stop loss e prendere i prezzi di profitto, BuyTakeProfit e
BuyStopLoss. Il numero di elementi della matrice deve essere indicato quando si dichiara la matrice. indici di matrice iniziano da zero, così

dichiarando una dimensione dimensione dell'array di 3, nostro indice di partenza è 0, e il nostro maggiore indice è 2.

Successivamente, si calcola lo stop loss e prendere i prezzi di profitto utilizzando le funzioni che abbiamo definito nel capitolo 4 -

CalcBuyStopLoss () e CalcBuyTakeProfit (). Assegniamo la perdita di arresto calcolata o prendiamo valore di profitto all'elemento matrice

appropriata. Si noti che il primo indice dell'array è 0 e l'indice terza schiera è


2.

Ecco il per ciclo per l'immissione degli ordini:

for (int count = 0; Conteggio <= MaxOrders - 1; Conte ++)


{Int OrdInt = Count + 1;

OrderSend (Simbolo (), OP_BUY, Misura di lotto, Ask, UseSlippage, BuyStopLoss [Conte],
BuyTakeProfit [Conte], "Buy Order" + OrdInt, MagicNumber, 0, verde); }

Il Contare variabile inizia a 0, a corrispondere con il primo elemento di matrice. Il numero di volte per ciclo ( vale a dire il numero di
ordini per disporre) è determinato dalla MaxOrders - 1. Per ogni iterazione del ciclo, viene incrementato lo stop loss e prendere profitto
array di uno.

134
Suggerimenti e trucchi

Noi usiamo il OrdInt variabile per incrementare il numero di ordine nel commento di ordine. Il primo commento ordine sarà "Buy Order 1", il

prossimo sarà "Buy Order 2" e così via. Il OrderSend () funzione inserisce l'ordine con la perdita di arresto appropriata e prendere il valore di

profitto, utilizzando la Contare variabile per selezionare l'elemento di matrice corrispondente.

Questo è solo un modo di gestire più ordini, anche se è probabilmente il più efficiente. Lo svantaggio principale di questo approccio è che
possiamo calcolare solo stop loss e prendere profitto dei prezzi per un numero limitato di ordini. In alternativa, potremmo scalare il take
profit e stop valori delle perdite per un ammontare prestabilito, e inserire un numero potenzialmente illimitato di ordini:

extern int StopLossStart = 20; extern int


StopLossIncr = 20;

extern int TakeProfitStart = 40; extern int


TakeProfitIncr = 40;

extern MaxOrders int = 5;

Nell'esempio sopra, la perdita di arresto per il primo ordine sarà di 20 pip. Noi incrementare lo stop loss di 20 pip per ogni
ulteriore ordine. Lo stesso per il take profit, tranne che inizieremo a 40 e l'incremento da 40. Invece di usare le matrici,
calcoleremo lo stop loss e prendere profitto nel per
ciclo continuo:

for (int count = 0; Count <= MaxOrders - 1; Count ++)


{Int OrdInt = Count + 1;

int = UseStopLoss StopLossStart + (StopLossIncr * Count); int = UseTakeProfit TakeProfitStart +


(TakeProfitIncr * Count);

doppia BuyStopLoss = CalcBuyStopLoss (Simbolo (), UseStopLoss, Ask); doppia BuyTakeProfit = CalcBuyTakeProfit
(Simbolo (), UseTakeProfit, Ask);

OrderSend (Simbolo (), OP_BUY, Misura di lotto, Ask, UseSlippage, BuyStopLoss,


BuyTakeProfit," Buy Order "+ OrdInt, MagicNumber, 0, verde);}

Noi determinare il take profit e Livello di Stop Loss in pips moltiplicando il StopLossIncr o
TakeProfitIncr variabile dal Contare, e aggiungendo che al StopLossStart o TakeProfitStart

valore. Per il primo ordine, lo stop loss o prendere livello di profitto sarà pari a StopLossStart o
TakeProfitStart.

Successivamente, si calcola lo stop loss e prendere prezzo profitto per l'ordine utilizzando le nostre funzioni dal capitolo 4. Infine abbiamo posto

l'ordine utilizzando OrderSend (). Il ciclo continuerà fino a quando il numero di ordini

135
E XPERT UN dvisor P ROGRAMMAZIONE

specificato da MaxOrders sono situati. Questo metodo ci permette di specificare come molti ordini come vogliamo utilizzare il MaxOrders
variabili, garantendo che ogni ordine abbiamo posto avrà uno stop loss e take profit.

Globale variabili

In questo libro, siamo stati riferiamo a variabili con un ambito globale come "variabili globali." MetaTrader ha un insieme di funzioni per

l'impostazione delle variabili a livello del terminale, il che significa che queste variabili sono disponibili per ogni consulente esperto

attualmente in esecuzione, supponendo che conosciamo il nome della variabile per iniziare.

La documentazione MQL si riferisce a questi come "variabili globali", anche se un nome più appropriato potrebbe essere "variabili
terminali". Usiamo le funzioni variabili globali nella Guida di riferimento sotto MQL
Le variabili globali per lavorare con questi tipi di variabili. L'attuale elenco di variabili globali nel terminale può essere
visualizzato selezionando Variabili globali dal Utensili menu o premendo F3 sulla tastiera.

Un modo di usare queste variabili è memorizzare alcune variabili ambito globale o statico al terminale, in modo che se un consulente esperto è

spento, possiamo raccogliere dove abbiamo lasciato. Non tutti i consulenti esperti richiedono questo, ma consulenti esperti più complesse

manterranno un certo stato che, se interrotto, sarà buttare fuori il funzionamento del consulente esperto.

Il modo migliore per evitare questo è di evitare la creazione di consulenti esperti che necessitano di un tale livello di complessità. Ma se non può essere

evitato, quindi utilizzando funzioni variabili globali per memorizzare lo stato corrente al terminale può essere utile in caso di spegnimento accidentale. Si noti

che questo metodo non è infallibile, ma è probabile che il metodo migliore per raggiungere questo obiettivo.

Per dichiarare una variabile globale (terminale), utilizzare la GlobalVariableSet () funzione. Il primo argomento è una stringa che indica
il nome della variabile globale, e il secondo è un valore di tipo double da assegnare ad esso.

GlobalVariableSet (GlobalVariableName, doubleValue);

Per mantenere i nomi delle variabili unica, si potrebbe desiderare di creare un prefisso variabile globale. Dichiarare una variabile ambito a livello globale

nel vostro consulente esperto, e impostare il valore della dentro() la funzione, utilizzando il simbolo corrente, periodo, il nome del consulente esperto e

numero magico per creare un prefisso variabile univoco.

136
Suggerimenti e trucchi

// Le variabili globali stringa


GlobalVariablePrefix;

int init ()
{GlobalVariablePrefix = Simbolo () + Periodo () + "_" + "ProfitBuster" + "_" + MagicNumber + "_"; }

Usiamo il simbolo e attuale periodo, insieme ad un identificatore per l'EA e la MagicNumber


variabile esterna. Ora, quando abbiamo fissato una variabile globale utilizzando GlobalVariableSet (), usiamo il prefisso che abbiamo definito

sopra, insieme con il nome della variabile attuale:

GlobalVariableSet (GlobalVariablePrefix + Counter, Counter);

Quindi, se stiamo negoziazione su EURUSD sul lasso di tempo M15 con un EA denominato "ProfitBuster", con 11 come il nostro numero magico e contatore

come il nostro nome della variabile, il nome della nostra variabile globale sarà

EURUSD15_ProfitBuster_11_Counter. È possibile utilizzare qualsiasi convenzione che si desidera per la denominazione le variabili globali, ma incluse le

informazioni di cui sopra è fortemente raccomandato.

Per recuperare il valore di una variabile globale, utilizzare la funzione GlobalVariableGet () con il nome della variabile come argomento:

Contatore = GlobalVariableGet (GlobalVariablePrefix + Counter);

Per eliminare una variabile globale, utilizzare la funzione GlobalVariableDel () con il nome della variabile come argomento. Per eliminare tutte le

variabili globali poste dal vostro EA, utilizzare la funzione

GlobalVariableDeleteAll () con il prefisso come argomento.

GlobalVariableDel (GlobalVariablePrefix + Counter); GlobalVariableDeleteAll


(GlobalVariablePrefix);

Per ulteriori informazioni sulle funzioni delle variabili globali, vedere la Le variabili globali argomento della MQL di riferimento.

Controllare Order Profit

A volte può essere utile per verificare il risultato corrente su un ordine, o per controllare il profitto totale su un ordine che è già chiuso. Ci

sono due modi per controllare il profitto. Per ottenere il profitto nella valuta di deposito, utilizzare il OrderProfit () funzione. È necessario

innanzitutto selezionare l'ordine utilizzando OrderSelect ().

137
E XPERT UN dvisor P ROGRAMMAZIONE

OrderSelect (biglietteria, SELECT_BY_TICKET); doppia GetProfit


= OrderProfit (biglietteria);

Il risultato della OrderProfit () funzione dovrebbe essere identico al profitto totale o la perdita che è elencato nella cronologia degli ordini per

l'ordine selezionato.

Per recuperare l'utile o la perdita in pips, è necessario calcolare la differenza tra il prezzo di apertura ordine e il prezzo di chiusura
ordine. Sarà inoltre necessario utilizzare il OrderSelect () funzione per recuperare i prezzi di apertura e chiusura.

OrderSelect (biglietteria, SELECT_BY_TICKET);

if (OrderType () == OP_BUY) doppia GetProfit = OrderClosePrice () - OrderOpenPrice (); else if (OrderType () == OP_SELL) GetProfit =
OrderOpenPrice () - OrderClosePrice ();

GetProfit / = PipPoint (Simbolo ());

Per ordini di acquisto, si calcola il profitto sottraendo il prezzo di apertura dal prezzo di chiusura. Per ordini di vendita, noi facciamo il

contrario. Dopo che abbiamo calcolato la differenza, siamo in grado di convertire l'utile o la perdita di un numero intero dividendolo per il

punto, utilizzando il nostro PipPoint () funzione.

Ad esempio, se il nostro prezzo di apertura buy ordine è 1,4650 e il nostro prezzo di chiusura è 1.4700, la differenza tra OrderClosePrice
() e OrderOpenPrice () è 0,0050. Se dividiamo che dal nostro

PipPoint () la funzione, il risultato è 50. Così, per questo ordine, facciamo 50 pips in profitto. Se il prezzo di chiusura ordine era 1.4600, invece,

allora avremmo una perdita di -50 pips.

Martingale

Martingale è un sistema di scommesse, comunemente usato in roulette e blackjack, dove la dimensione scommessa viene raddoppiato dopo ogni perdita

consecutiva. La teoria è che una scommessa vincente porterà l'equilibrio torna a chiudere in pareggio. L'aspetto negativo di Martingale è che avete

bisogno di un sacco di capitale per resistere alle prelievi.

Ad esempio, se la dimensione del lotto di partenza è di 0,1 lotti, dopo 4 sconfitte consecutive la tua dimensione del lotto sarà di 1,6 lotti

- 16 volte la dimensione del lotto originale. Dopo 7 sconfitte consecutive, la vostra dimensione del lotto sarà 12,8 lotti - 128 volte la dimensione originale del

lotto! Una lunga serie di sconfitte asciugherà tuo account prima che sarete in grado di portare il tuo account di nuovo per andare in pari.

Tuttavia, si potrebbe desiderare di incorporare un sistema di aumentare le dimensioni dei lotti sulle vincite o perdite consecutive, ed è possibile

farlo senza cancellare il tuo account. Il metodo più semplice è quello di mettere un limite al numero di volte per aumentare la dimensione del lotto.

Un sistema di trading suono non dovrebbe avere più di 3

138
Suggerimenti e trucchi

o 4 perdita massima consecutivi. È possibile determinare questo esaminando il numero massimo di perdita consecutiva sotto la rapporto
scheda nella finestra Strategy Tester.

Un altro metodo è quello di aumentare la dimensione del lotto da un moltiplicatore più piccolo. La classica strategia Martingale raddoppia la dimensione del

lotto dopo ogni perdita consecutiva. Si potrebbe desiderare di utilizzare un moltiplicatore più piccolo di 2. V'è anche la strategia anti-Martingale, in cui si

aumenta la dimensione del lotto dopo ogni vittoria consecutiva.

Esaminiamo una routine in cui si calcola il numero di vittorie o di sconfitte consecutive, e aumentare la dimensione del lotto di conseguenza. Una

strategia Martingale funziona meglio quando si sta posizionando un ordine alla volta, quindi si suppone che ogni posizione è costituito da un singolo

commercio.

L'utente sarà in grado di scegliere tra una Martingale (perdite) o anti-martingala strategia (vittorie). Un'impostazione di limitare
sarà incluso il numero massimo di aumenti lotto consecutivi, e il moltiplicatore lotto sarà regolabile.

In primo luogo, cerchiamo di calcolare il numero di vittorie o di sconfitte consecutive. Avremo bisogno di scorrere la cronologia degli ordini
piscina a ritroso, a partire dalla fine più recentemente chiuso. Noi incrementare un contatore per ogni vittoria o la perdita. Finché un
modello di vincite o perdite consecutive viene mantenuta, si continuerà a ciclo. Non appena il modello è rotto (una vittoria si trova dopo una
o più perdite, o viceversa), il ciclo terminerà.

int WinCount; int


LossCount;

for (int Count = OrdersHistoryTotal () - 1; ; Contare--)


{OrderSelect (Conte, SELECT_BY_POS, MODE_HISTORY);

if (OrderSymbol () == Simbolo () && OrderMagicNumber () == MagicNumber)


{ if (OrderProfit ()> 0 && LossCount == 0) WinCount ++;

else if (OrderProfit () <0 && WinCount == 0) LossCount ++; altro break; }}

Iniziamo dichiarando le variabili per i nostri contatori di vittoria e di perdita. Nel per operatore, si noti che usiamo OrdersHistoryTotal () di
stabilire la nostra posizione di partenza iniziale. OrdersHistoryTotal () restituisce il numero di ordini nel pool storia. Si sottrae 1 per
determinare la posizione di indice per l'ordine più recente, che è memorizzato nella Contare variabile.

Si noti che abbiamo omesso la seconda espressione nella per loop - quello che determina la condizione di fermare il ciclo. Il
punto e virgola deve rimanere per eventuali espressioni omessi. Noi diminuire il Contare variabile su ogni iterazione del ciclo.

139
E XPERT UN dvisor P ROGRAMMAZIONE

Noi usiamo MODE_HISTORY come terzo parametro nel OrderSelect () la funzione per indicare che stiamo scorrendo la piscina cronologia degli ordini

chiusi. Per impostazione predefinita, OrderSelect () utilizza la piscina ordine sparso, quindi dobbiamo specificare MODE_HISTORY quando si controlla

la piscina ordine chiuso.

Controlliamo per assicurarsi che l'ordine attualmente selezionato corrisponda il nostro simbolo sulla carta e il nostro numero magico. Poi, si

esamina il profitto ordine utilizzando il OrderProfit () funzione. Se il valore restituito indica un profitto ( vale a dire è maggiore di zero), allora viene

incrementato il WinCount variabile. Se si tratta di una perdita, incrementiamo LossCount.

Poiché stiamo cercando vittorie o perdite consecutive, dobbiamo terminare il ciclo una volta trovata una condizione alternata. Per fare
questo, controlliamo il WinCount o LossCount variabile quando il controllo del profitto ordine. Per esempio, se abbiamo 2 sconfitte
consecutive - il che significa che LossCount = 2 - e il nostro prossimo ordine è una vittoria, allora entrambi il nostro Se dichiarazioni saranno
falsi, e il controllo passerà al rompere operatore, che termina il ciclo.

Il vantaggio di questo metodo è che è robusta, e non mancherà, se il consulente esperto viene accidentalmente spento. La EA riprendere
da dove si era interrotto. Naturalmente, questo significa che quando si inizia l'EA, userà qualsiasi precedente striatura di vittoria / perdita
per determinare la dimensione del lotto. Ma come si può vedere, i vantaggi superano gli svantaggi.

O il WinCount o il LossCount variabile conterrà il numero di vittorie o perdite consecutive. Se vogliamo fare una strategia Martingale,
usiamo LossCount per determinare il fattore per il quale per aumentare la dimensione del lotto. Se stiamo facendo un anti-martingala,
usiamo WinCount anziché.

Useremo una variabile intera chiamata esterna MartingaleType per determinare questo. Se MartingaleType
è impostato su 0, useremo la strategia Martingale. Se è impostato su 1, useremo la strategia anti-Martingale. Ci sarà anche dichiarare le variabili

esterne per il nostro moltiplicatore ( LotMultiplier), il numero massimo di volte per aumentare la dimensione del lotto ( MaxMartingale), e la nostra

dimensione del lotto di partenza ( BaseLotSize).

// Le variabili esterne
extern int MartingaleType = 0; // 0: Martingale, 1: Anti-Martingale
extern int LotMultiplier = 2; extern int MaxMartingale =
4; extern double BaseLotSize = 0,1;

// calcolo della dimensione del lotto


if (MartingaleType == 0) int = ConsecutiveCount LossCount; else if (MartingaleType = 1) =
ConsecutiveCount WinCount;

if (ConsecutiveCount> MaxMartingale) ConsecutiveCount = MaxMartingale;

Misura di doppia = BaseLotSize * MathPow (LotMultiplier, ConsecutiveCount);

140
Suggerimenti e trucchi

Abbiamo impostato il valore di ConsecutiveCount per entrambi WinCount o LossCount, dipende da


MartingaleType ambientazione. Ci Confronti che, per il nostro MaxMartingale ambientazione. Se il nostro conteggio ordine consecutivo è maggiore di MaxMartingale, ci

ridimensionerà che sia pari a MaxMartingale. ( Si potrebbe anche ridimensionarla per la dimensione del lotto di default, se si preferisce). La dimensione del lotto

rimarrà a questa dimensione fino a quando una vittoria o perdita rompe la nostra striscia ordine consecutivo.

La dimensione del lotto è determinato moltiplicando la nostra BaseLotSize dal LotMultiplier, che è esponenzialmente aumentato di ConsecutiveCount.
Il MathPow () funzione solleva un numero alla potenza specificata. Il primo argomento è la base, e il secondo argomento è l'esponente.
Ad esempio, se la nostra dimensione del lotto di partenza è di 0,1, il moltiplicatore molto è 2, e abbiamo quattro ordini consecutivi,
l'equazione è 0,1 * 2 4 = 1.6.

Regolando la LotMultiplier e utilizzando sia Martingale e strategie anti-martingala, questo vi darà abbastanza opzioni di sperimentare con l'utilizzo di

sacco dimensionamento esponenziale. Si può facilmente modificare il codice qui sopra per utilizzare altre varianti. Ad esempio, è possibile scalare

le dimensioni dei lotti in senso inverso, dal più grande al più piccolo. Oppure si potrebbe utilizzare un contatore esterno al posto di ConsecutiveCount.

Debug Expert Advisor

Diversamente dalla maggior parte IDE di programmazione, MetaEditor non supporta i punti di interruzione o di qualsiasi altro tipo di moderne tecniche di debug.

Avrete bisogno di usare Stampare() dichiarazioni e registri per eseguire il debug consulenti esperti.

Hai già stato introdotto al Stampare() funzione. In sintesi, qualsiasi argomento di tipo stringa passata alla funzione verrà stampato al
registro. Stampando il contenuto delle variabili e funzioni per il registro, è possibile esaminare l'output del codice e correggere
eventuali errori.

Ti consigliamo di utilizzare il tester strategia di eseguire una simulazione di trading ed esaminare l'output del registro. Il registro Strategia Tester

viene visualizzata sotto il rivista scheda nella finestra Strategy Tester. C'è un limite alla quantità di informazioni che è elencato nella scheda ufficiale,

quindi si consiglia di visualizzare il registro vero e proprio.

I registri Strategia Tester sono memorizzati nella cartella \ tester \ logs cartella. Tasto destro del mouse in qualsiasi punto della finestra di Journal

e selezionare Aperto dal menu a comparsa. Si aprirà una finestra di Esplora risorse, che visualizza il contenuto della cartella di registro. I nomi

dei file sono in formato yyyymmdd.log, dove aaaa è l'anno di quattro cifre, mm è il mese a due cifre, e dd è la data a due cifre. È possibile

visualizzare i log in Blocco note o qualsiasi editor di testo.

Illustriamo un esempio di come è possibile utilizzare il registro per individuare un problema di programmazione. Il codice qui sotto ha un errore in esso,

e non funziona come ci aspettavamo. Per essere in grado di diagnosticare il problema,

141
E XPERT UN dvisor P ROGRAMMAZIONE

dobbiamo controllare l'ingresso o l'uscita della funzione. Creiamo un Stampare() dichiarazione e stampare il contenuto di tutte le variabili
rilevanti per il registro.

Faremo l'EA nel Tester strategia, utilizzando solo prezzi di apertura come il nostro modello di test. Assicurarsi che si sta testando l'EA nel corso di un

periodo di tempo abbastanza lungo in modo che possa posto abbastanza mestieri per di analizzare. Se è necessario per verificare i prezzi sul grafico, ha

colpito la aperto Grafico pulsante per aprire un grafico che mostra i traffici simulati.

Successivamente, andremo alla scheda ufficiale e controllare le informazioni di cui abbiamo bisogno. Se abbiamo bisogno di visualizzare il registro nella sua

interezza, o se ci sono mestieri che non vengono visualizzati nella scheda ufficiale, siamo in grado di fare clic destro e scegliere Apri dal menu a comparsa, e aprire

direttamente il file di log.

Questo codice ci sta dando errore 130: "fermate non validi" ogni volta che abbiamo posto un ordine di acquisto. Sappiamo che l'errore 130

significa che o lo stop loss o take profit non è corretto. Riuscite a identificare l'errore?

if (Chiudi [0]> MA && BuyTicket == 0)


{Double OpenPrice = Chiedi;

doppio BuyStopLoss = OpenPrice + (StopLoss * UsePoint); doppio BuyTakeProfit = OpenPrice +


(TakeProfit * UsePoint);

BuyTicket = OrderSend (Simbolo (), OP_BUY, Misura di lotto, OpenPrice, UseSlippage,


BuyStopLoss, BuyTakeProfit, "Buy Order", MagicNumber, 0, verde);

SellTicket = 0; }

Useremo il Stampare() funzione per verificare i parametri che vengono passati al OrderSend ()
funzione. Ci concentriamo sul prezzo di apertura ordine, lo stop loss e take profit.

Stampa ( "Prezzo:" + OpenPrice + "Stop: "+ BuyStopLoss +" Profit:" + BuyTakeProfit);

Qui è l'uscita quando si corre l'EA nel tester strategia. Uno stop loss e take profit di 50 pips si presume:

11:52:12 2009.11.02 02:00 Esempio EURUSD, H1: OrderSend errore 130 11:52:12 2009.11.02 02:00 Esempio EURUSD, H1: Prezzo:
1,47,34 milioni di arresto: 1,47,84 milioni
Utile: 1.47840000

Sappiamo che la perdita di arresto deve essere al di sotto del prezzo di apertura per un ordine di acquisto. Qui, è superiore al prezzo. In realtà, è lo

stesso prezzo come il take profit. Un rapido sguardo al nostro codice e ci rendiamo conto che abbiamo accidentalmente inseriti un segno più

nell'equazione buy stop loss. Ecco il codice corretto:

142
Suggerimenti e trucchi

doppia BuyStopLoss = OpenPrice - (StopLoss * UsePoint);

Se si riceve un messaggio di errore quando si tenta di inserire, chiudere o modificare un ordine, concentrare gli sforzi sul problema
indicato dal messaggio di errore. Qui ci sono un paio di messaggi di errore causa più comune da errori di programmazione:

• Errore 129: Prezzo non valido - Il prezzo di apertura è valido. Per ordini di mercato, assicurarsi che l'attuale offerta o Chiedi viene

passato dei prezzi, a seconda del tipo di ordine. Per gli ordini in attesa, assicurarsi che il prezzo è al di sopra o al di sotto del prezzo

corrente, come richiesto dal tipo di ordine. Anche controllare per vedere che il prezzo ordine in corso non è troppo vicino al prezzo

corrente ( vale a dire all'interno del livello di stop).

• Errore 130: Interrompe non validi - O lo stop loss o prendere prezzo profitto non è corretto. Verificare che lo stop loss e prendere

profitto prezzi sono posizionati al di sopra o al di sotto del prezzo corrente, a seconda se il tipo di ordine è acquistare o vendere.

Anche controllare per vedere che lo stop loss o prendere prezzo profitto non è troppo vicino al prezzo corrente ( vale a dire all'interno

del livello di stop).

• Errore 131: Invalid Scambi - La dimensione del lotto è corretto. Assicurarsi che il lotto non superi il minimo broker o
massimo, e che la dimensione del lotto è normalizzato al valore del passo corretto (0.1 o 0.01 sulla maggior parte dei
broker).

Le descrizioni di tutti i messaggi di errore possono essere trovati nella Guida di riferimento sotto MQL Costanti standard - codici di errore. Se avete

bisogno di ulteriore assistenza con un errore che si sta ricevendo, controllare il forum a MQL4.com.

Risoluzione dei problemi Errori Trading intermittenti

Mentre la maggior parte i bug gravi possono essere trovati semplicemente test retrospettivi, gli altri avranno luogo solo durante la negoziazione in tempo reale. Gli errori

di logica può portare a traffici non essere posizionati in modo corretto, e questi bug possono richiedere un certo sforzo per individuare. Se ci sono commerci di essere

immessi in modo non corretto durante la demo o trading dal vivo, abbiamo bisogno di quante più informazioni necessarie per risolvere il problema.

Stiamo per aggiungere una funzione opzionale per registrare il commercio e lo stato informazioni in tempo reale, in modo da avere un record di esso

durante la risoluzione dei mestieri. Useremo Stampare() affermazioni come in precedenza, ma saremo di registrazione valori degli indicatori, i prezzi - tutte

le informazioni che saranno utili per il debug. Aggiungeremo anche una variabile esterna per accendere la registrazione on e off.

// Le variabili esterne extern bool Debug =


true;

143
E XPERT UN dvisor P ROGRAMMAZIONE

// posto vicino alla fine della funzione start ()


if (debug == true) Stampa (StringConcatenate ( "Offerta", Bid, "Chiedi:" Chiedi, "MA:", MA,
"BuyTicket:", BuyTicket, "SellTicket:", SellTicket));

Il codice qui sopra prezzo e informazioni indicatore, così come il contenuto del log Comprare un biglietto e
SellTicket variabili. Se ci sono domande su come un commercio è stato aperto, o perché un commercio non è stato aperto, il registro in quel

particolare momento mostrerà lo stato di tutte le condizioni commerciali rilevanti. È possibile attivare la registrazione e si spegne con il mettere a

punto variabile esterna.

il di debug Stampare() dichiarazione deve essere posizionato vicino alla fine della inizio() la funzione, dopo tutte le funzioni di trading. Se si

utilizza un timer e / o un eseguire al bar caratteristica aperto, posizionare il debug di

Stampare() istruzione all'interno del blocco timer in modo che venga eseguito solo quando è necessario. In caso contrario, la linea di debug

stamperà nel log su ogni tick, che può risultare in un grande file di log.

La correzione degli errori di compilazione

Quando si compila il consulente esperto, il compilatore verifica la presenza di sintassi corretta, e garantire che tutte le funzioni personalizzate e le

variabili sono stati correttamente dichiarati. Se hai lasciato qualcosa, il compilatore si fermerà, e gli eventuali errori di compilazione apparirà nella Errori

linguetta nel cassetta degli attrezzi finestra.

Di fronte a una lunga lista di errori di compilazione, iniziare sempre con il primo. Fare doppio clic sul errore nella lista, e
l'editor salterà direttamente alla linea con l'errore. Correggere l'errore e ricompilare. A volte un semplice errore di sintassi si
tradurrà in diversi errori non correlati, anche se solo il primo era valida.

Ecco un elenco di errori di compilazione comuni e le loro soluzioni:

• Variabile non definita - Hai dimenticato di dichiarare una variabile con un tipo di dati. Se si tratta di una variabile globale o esterno, dichiararla

nella parte superiore del file. Se si tratta di una variabile locale, trovare la prima occorrenza e posizionare la dichiarazione del tipo di dati di fronte

ad essa. In caso contrario, il controllo ortografico o il caso (superiore / inferiore) del nome della variabile.

• Variabile già definito - È dichiarato la stessa variabile due volte. Rimuovere la dichiarazione del tipo di dati da tutte le
dichiarazioni di variabili duplicati.

• La funzione non è definita - Se la funzione in questione è in un file di inclusione o libreria, essere sicuri che il # includere o # importare
direttiva è posizionato nella parte superiore del file ed è corretto. In caso contrario, controllare l'ortografia o il caso del nome
della funzione, ed essere sicuri che esiste sia nel file corrente o nel relativo includere o file di libreria.

144
Suggerimenti e trucchi

• Assegnazione non valida usato - Questo è di solito in riferimento ad un segno di uguale (=). Ricordate che un singolo segno di

uguale è per l'assegnazione variabile e due segni di uguale (==) è un operatore di confronto. Correggere l'operatore di assegnazione

per l'operatore di confronto appropriata.

• Assegnazione previsto - Questo è di solito in riferimento alla operatore di confronto "uguale a" (==). Hai usato due segni uguali
invece di uno in un assegnamento di variabile. Correggere l'operatore ad un unico segno di uguale.

• Sbilanciato parentesi - Questi di solito si verificano in un Se dichiarazione quando si utilizza parentesi nidificate. Vai
alla linea indicata dal primo errore e inserire una parentesi aperta in un luogo adeguato.

• Sbilanciato parentesi sinistra - Questo è un ingannevole. L'errore di solito indica la fine della riga di programma. In sostanza si è

dimenticato una parentesi chiusa da qualche parte. Doppio controllare il codice di recente modificato e cercare una parentesi destra

manca. Potrebbe essere necessario commentare righe di codice per individuare il problema.

• contano i parametri errati - Hai troppo pochi o troppi argomenti in una funzione. Doppio controllare la
sintassi funzione nel MQL di riferimento e correggere gli argomenti.

• Punto e virgola previsto - Probabilmente si è dimenticato di mettere un punto e virgola alla fine di una riga. Mettere un punto e virgola alla fine

della riga precedente. Si noti che la mancanza di un punto e virgola può causare degli errori di cui sopra e, in modo da essere sicuri di mettere

quei punti e virgola!

145
E XPERT UN dvisor P ROGRAMMAZIONE

Capitolo 9
Indicatori personalizzati e script

Nessun libro sulla MQL sarebbe completa senza coprire gli indicatori personalizzati e script. Gli indicatori incorporati in MetaTrader
sono piuttosto limitati, ma per fortuna MQL consente ai programmatori di creare i propri indicatori. Se siete alla ricerca di un
indicatore popolare che non è incluso nel MT4, è probabile che qualcuno ha già creato uno.

Questo capitolo sarà una panoramica di base della creazione indicatore personalizzato. La maggior parte degli indicatori sono basati su formule

matematiche complesse, e come tali sono il dominio di programmatori più esperti. Tuttavia, un indicatore non deve essere complessa. Creeremo un

indicatore personalizzato in questo capitolo che utilizza solo poche righe di codice.

buffer

Buffer sono matrici che memorizzano valori degli indicatori e calcoli. Un indicatore personalizzato può avere fino a 8 buffer. Buffer utilizzare gli

indici, proprio come gli array fanno, e vanno da 0 a 7. Quando si chiama un indicatore personalizzato in un consulente esperto utilizzando il iCustom

() funzione, il parametro successivo per durare nella funzione è il buffer indicatore.

Per trovare il buffer appropriato per una linea dell'indicatore, è solito controllare il codice sorgente, se disponibile. Se il codice sorgente è chiaramente

formattato con i nomi delle variabili descrittive, si dovrebbe essere in grado di identificare il tampone appropriato abbastanza facilmente. Affronteremo

la corretta denominazione di indicatori buffer in questo capitolo.

Creazione di un indicatore personalizzato

Costruiamo un indicatore personalizzato utilizzando due indicatori MetaTrader built-in per calcolare le nostre linee. Stiamo per costruire un

indicatore di Bande di Bollinger modificato. Le bande di Bollinger sono costituite da 3 linee - una linea centrale che è una media mobile semplice,

insieme ad una linea superiore e inferiore cui valore è determinato dalla deviazione standard.

Siamo in grado di creare la nostra indicatore Bollinger Bands utilizzando la media mobile e gli indicatori di deviazione standard.
Vorremmo creare un indicatore che utilizza una media mobile esponenziale per calcolare le linee, al contrario di una media mobile
semplice.

146
Indicatori personalizzati e script

Iniziamo utilizzando la procedura guidata per creare il nostro file indicatore. Selezionare Nuovo dal menu File o sulla barra degli strumenti per aprire la procedura

guidata e creare un indicatore personalizzato. Compila il nome dell'indicatore, e aggiungere i parametri, se lo si desidera. Nella pagina finale, abbiamo aggiunto

tre linee indicatrici dello stesso colore. Ecco il risultato della procedura guidata. Abbiamo lasciato la inizio() Funzione per ora:

// + ----------------------------------------------- ------------------- + // |
EMA Bollinger.mq4 |
// | Andrew Young |
// | http://www.easyexpertforex.com |
// + ----------------------------------------------- ------------------- +
# protette da copyright "Andrew Young"
# Link immobili "Http://www.easyexpertforex.com"

# immobili indicator_chart_window
# indicator_buffers proprietà 3
# immobili indicator_color1 DeepSkyBlue
# immobili indicator_color2 DeepSkyBlue
# immobili indicator_color3 DeepSkyBlue
// ---- buffer
doppia ExtMapBuffer1 []; doppia
ExtMapBuffer2 []; doppia
ExtMapBuffer3 [];
// + ----------------------------------------------- ------------------- + // | funzione dell'indicatore inizializzazione personalizzata
|
// + ----------------------------------------------- ------------------- + int init ()

{
// ---- indicatori
SetIndexStyle (0, DRAW_LINE); SetIndexBuffer (0,
ExtMapBuffer1); SetIndexStyle (1, DRAW_LINE);
SetIndexBuffer (1, ExtMapBuffer2); SetIndexStyle
(2, DRAW_LINE); SetIndexBuffer (2,
ExtMapBuffer3);

// ----
ritorno (0); }

Facciamo la nostra attenzione agli elementi elencati in grassetto. Il # proprietà dichiarazioni impostare i parametri per il nostro indicatore
buffer. Il indicator_chart_window proprietà attira la nostra indicatore nella finestra del grafico principale. Se stavamo creando un oscillatore,
e volevamo attirare l'indicatore in una finestra separata, avremmo usato il indicator_separate_window proprietà invece.

Il indicator_buffers Proprietà impostare il numero di buffer per il nostro indicatore. In questo caso stiamo usando tre buffer. Il indicator_color
proprietà impostano il colore di tutte le tre linee di DeepSkyBlue.

147
E XPERT UN dvisor P ROGRAMMAZIONE

Seguono poi le dichiarazioni per i nostri matrici di memorizzazione temporanea. Abbiamo tre buffer di nome ExtMapBuffer ( 1-3).

Cambieremo questi identificatori degli array a qualcosa di più descrittivo a breve.

Il dentro() funzione è dove abbiamo impostato le proprietà per il nostro indicatore buffer. SetIndexBuffer ()
lega una matrice di memorizzazione temporanea di un indice di buffer. L'indice di buffer è quello che ci riferiamo quando abbiamo impostato le proprietà di

una linea dell'indicatore, e anche quando chiamiamo una linea indicatore da un EA utilizzando le

iCustom () funzione. Il primo parametro è un numero intero da 0 a 7, e il secondo parametro è il nome della matrice tampone.

Disegno Proprietà

Il SetIndexStyle () funzione imposta il tipo di linea per disegnare, insieme con le proprietà di tale linea. Ogni linea indicatore
avrà un corrispondente SetIndexStyle () funzione. Ecco la sintassi:

SetIndexStyle void (int BufferIndex, int Modello di linea, int LineStyle = VUOTO,
int LineWidth = VUOTO, colore LineColor = CLR_NONE)

• BufferIndex - L'indice del buffer, da 0 a 7.

• Modello di linea - Imposta il tipo di linea da disegnare. DISEGNARE LA LINEA disegna una singola linea, DRAW_HISTOGRAM

disegna un istogramma verticale (vedi OSMA o indicatori Awesome Oscillator per esempio),
DRAW_ARROW disegna un simbolo, e DRAW_NONE disegna nessuna linea.

• LineStyle - Un parametro opzionale che indica lo stile di disegno. Utilizzato principalmente per le linee di tipo

DISEGNARE LA LINEA. Per impostazione predefinita, una linea continua è disegnata ( STYLE_SOLID). Si può anche disegnare tratteggiata ( STYLE_DASH)

e punteggiato ( STYLE_DOT) Linee.

• Larghezza della linea - Un parametro opzionale che indica la larghezza della linea in pixel. Il valore predefinito è 1.

• LineColor - Un parametro opzionale che indica il colore della linea. Se si utilizza la procedura guidata, il colore è impostato usando # proprietà

dichiarazioni, ma è possibile impostare il colore anche qui.

Se si utilizza DRAW_ARROW come il Modello di linea, il SetArrow () funzione permette di impostare il simbolo di carattere Wingdings per
disegnare sul grafico. Il primo parametro è l'indice del buffer, e la seconda è una costante intero che rappresenta il simbolo per disegnare. I
simboli possono essere trovati nella Guida di riferimento sotto MQL Costanti Standard - Codici freccia.

Si consiglia di aggiungere una descrizione per le linee degli indicatori che verranno visualizzate nella descrizione comandi o nella finestra dei dati. Per

fare questo, utilizzare la SetIndexLabel () funzione. Il primo parametro è l'indice del buffer, e il secondo parametro è una descrizione testuale.

Aggiungeremo questi per il nostro indicatore a breve.

148
Indicatori personalizzati e script

Se il vostro indicatore è disegnato in una finestra separata (come ad esempio un oscillatore), e ti piacerebbe aggiungere livelli per indicare
i livelli di ipercomprato o ipervenduto (come negli indicatori stocastici o RSI), o il livello zero (come nel CCI indicatore), è possibile
utilizzare il SetLevelStyle () e SetLevelValue () funzioni. Vedere il riferimento MQL sotto indicatori personalizzati per maggiori informazioni.

Si consiglia inoltre di specificare un nome breve indicatore deve essere visualizzato nell'angolo in alto a sinistra della finestra di indicazione. Utilizzare il IndicatorShortName

() funzione per impostare questo valore. L'unico parametro è una stringa di testo che verrà visualizzato nell'angolo in alto a sinistra della finestra

dell'indicatore, così come nella finestra dei dati.

Utilizzando descrittive nomi Buffer

Ecco il nostro codice indicatore aggiornato. Si noti che abbiamo ribattezzato matrici di memorizzazione temporanea per essere più descrittivo

riguardo alla loro funzione reale. Abbiamo cambiato il secondo parametro della SetIndexBuffer () funzioni per riflettere i nuovi nomi di buffer. Abbiamo

anche aggiunto SetIndexLabel () per ogni linea per visualizzare i nomi descrittivi nella finestra dei dati.

// ---- buffer doppio EMA


[];
Doppio UpperBand [];
Doppio LowerBand [];
// + ----------------------------------------------- ------------------- + // | funzione dell'indicatore inizializzazione personalizzata
|
// + ----------------------------------------------- ------------------- + int init ()

{
// ---- indicatori
SetIndexStyle (0, DRAW_LINE);
SetIndexBuffer (0, EMA); SetIndexLabel (0,
"EMA");

SetIndexStyle (1, DRAW_LINE); SetIndexBuffer


(1, UpperBand); SetIndexLabel (1,
"UpperBand");

SetIndexStyle (2, DRAW_LINE); SetIndexBuffer


(2, LowerBand); SetIndexLabel (2,
"LowerBand");
// ----
ritorno (0); }

Abbiamo rinominato nostre matrici di memorizzazione temporanea dei nomi predefiniti ( ExtMapBuffer) a quelli più descrittivi.

EMA [] sarà il nostro buffer per la linea centrale, e UpperBand [] e LowerBand [] saranno rispettivamente le bande superiore ed

inferiore.

149
E XPERT UN dvisor P ROGRAMMAZIONE

Il SetIndexBuffer () funzioni legano gli indici del buffer per le nostre matrici di memorizzazione temporanea. EMA è 0, UpperBand è

1, e LowerBand è 2. Si noti che le parentesi sono lasciati fuori del nome identificatore array per la seconda
SetIndexBuffer () parametro.

Il SetIndexLabel () funzioni impostano un nome descrittivo per ciascuno degli indicatori buffer. In questo caso, i nomi linea sono gli stessi
nostri nomi identificatore. Questi appariranno sul tooltip del mouse così come nella finestra dati. Se un altro programmatore decide di
utilizzare questo indicatore in un consulente esperto, la formattazione sopra chiarirà esattamente quale indice indicatore tampone
dovrebbero utilizzare per ogni linea.

L'inizio indicatore () Funzione

La procedura guidata inserisce una sola espressione nel inizio() funzione:

int = counted_bars IndicatorCounted ();

IndicatorCounted () restituisce il numero di barre nel grafico che l'indicatore è già calcolato. Quando la EA primo avvio, questo

valore sarà 0. L'indicatore verrà calcolato per ogni bar sul grafico. Su barre successive, si provvederà a controllare la IndicatorCounted
() funzione per vedere quanti bar sono già stati calcolati, in modo sapremo esattamente quanti bar nuovo abbiamo bisogno di

calcolare.

I nostri calcoli indicatore si verificheranno all'interno di un per ciclo continuo. Il punto di partenza sarà la prima barra uncalculated, e il
punto finale sarà barra corrente. Ci confrontiamo il valore di IndicatorCounted () al predefinito Barre variabile, che restituisce il numero di
barre sul grafico corrente. Questo determinerà il nostro punto di partenza. Ecco il codice per la per ciclo continuo:

int = counted_bars IndicatorCounted ();

if (counted_bars> 0) counted_bars--;

int CalculateBars = Bar - counted_bars;

for (int conte = CalculateBars; Conteggio> = 0; Count--)


{ // calcoli Indicatore}

Il primo Se dichiarazione sarà diminuire il valore di counted_bars da 1 nel calcolo nuovi bar. Saremo sempre calcolando almeno due
barre precedenti. Ciò è dovuto ad una condizione in cui il battito finale di una barra non può essere calcolato in alcuni casi.
Successivamente, si determina il numero di barre da calcolare, sottraendo counted_bars dal predefinito Barre variabile. Questo è
memorizzato nella variabile CalculateBars.

150
Indicatori personalizzati e script

Nel nostro per ciclo, la variabile incrementando Contare è impostato al valore di CalculateBars, la condizione per la terminazione è quando Contare
è inferiore a 0, e Contare variabile viene decrementato ad ogni iterazione. Questo calcolerà ogni barra sul grafico da sinistra a destra.

Ecco il codice per calcolare le nostre bande di Bollinger. Ci dichiariamo la variabile esterna BandsPeriod all'inizio del file. Il per ciclo è
quello che abbiamo creato in precedenza:

// parametri esterni
extern int BandsPeriod = 20;

// funzione di avvio ()
for (int conte = CalculateBars; Conteggio> = 0; Count--)
{ EMA [Count] = iMA (NULL, 0, BandsPeriod, 0, MODE_EMA, 0, Count);

doppio StdDev = iStdDev (NULL, 0, BandsPeriod, 0, MODE_EMA, 0, Count);

UpperBand [count] = EMA [Conte] + StdDev; LowerBand


[Count] = EMA [count] - StdDev;
}

In primo luogo, che noi chiamiamo il built-in Moving indicatore di media con il io sono un() funzione, e assegnare il valore restituito EMA

[Conte]. Si noti che l'indice di matrice e la Cambio parametro per l'indicatore di media mobile sia utilizzare la corrente Contare valore.

Avanti, che noi chiamiamo l'indicatore di deviazione standard utilizzando iStdDev (). Per calcolare la banda superiore, tutto quello che dobbiamo fare è aggiungere la

deviazione standard alla linea di media mobile. Questo è memorizzato nella matrice di memorizzazione temporanea

UpperBand []. Calcolare LowerBand [], sottraiamo la deviazione standard dalla media mobile.

Estendiamo il nostro indicatore di un po 'di più dandogli una gamma completa di impostazioni. Aggiungeremo le impostazioni per regolare lo spostamento in

avanti, spostando il metodo della media, e applicato parametri di prezzo, così come una regolazione deviazione standard:

// esterno int parametri extern BandsPeriod =


20;
extern int BandsShift = 0; extern int
BandsMethod = 1; extern int BandsPrice =
0; Deviazioni extern int = 1;

151
E XPERT UN dvisor P ROGRAMMAZIONE

// funzione di avvio ()
for (int conte = CalculateBars; Conteggio> = 0; Count--)
{ EMA [count] = iMA (NULL, 0, BandsPeriod, BandsShift, BandsMethod, BandsPrice, Contare);

doppio StdDev = iStdDev (NULL, 0, BandsPeriod, BandsShift, BandsMethod, BandsPrice, Contare);

UpperBand [count] = EMA [count] + ( StdDev * Deviazioni);


LowerBand [Count] = EMA [count] - ( StdDev * Deviazioni);
}

Abbiamo aggiunto le variabili esterne per regolare i parametri rimanenti per la io sono un() e iStdDev ()
funzioni. Abbiamo anche aggiunto un parametro per regolare il numero di deviazioni standard. Per calcolare questo, abbiamo semplicemente

moltiplichiamo StdDev di Deviazioni. Ora abbiamo una completamente regolabile indicatore Bollinger Bands che è più flessibile rispetto l'indicatore

MetaTrader standard. Il codice completo è riportato in Appendice E.

Si può fare di più con indicatori personalizzati che solo ricalcolare indicatori incorporati. A seconda del livello di conoscenze matematiche,
è possibile codificare indicatori che non sono inclusi con MetaTrader, o addirittura creare il proprio. È anche possibile disegnare e
manipolare oggetti pure. Se vuoi saperne di più sulla creazione indicatore personalizzato, vedere gli argomenti di riferimento MQL indicatori
personalizzati, funzioni Object
e Math & Trig.

Script

Uno script è un programma MQL che viene eseguito solo una volta, quando viene prima attaccato a un grafico. Gli script possono essere utilizzati per

automatizzare una serie di azioni commerciali, come ad esempio la chiusura tutti gli ordini sul grafico o l'invio di un ordine pendente. Alcuni script, come il period_converter

script in dotazione con MetaTrader, possono ridisegnare il grafico basato su un periodo di tempo personalizzato.

Un file di codice sorgente script dovrebbe avere sia la show_confirm o show_inputs Direttiva proprietà. Il show_confirm Proprietà
chiede all'utente di confermare l'operazione dello script, mentre
show_inputs visualizza la finestra di proprietà di script.

# immobili show_confirm // mostra il dialogo che confermano


# show_inputs proprietà // mostra finestra delle proprietà

Se lo script ha dei parametri che devono essere adeguati, utilizzare il show_inputs proprietà. In caso contrario, utilizzare show_confirm.

152

Potrebbero piacerti anche