Por que NÃO existe uma EA completa dentro da Base de Código? - página 3

 
WHRoeder:
Aqui está a minha menos a lógica comercial real.
Eu tinha uma PM relativa ao filtro de tempo/dia de negociação. O pedido era 1800-0600 de segunda a sexta-feira. Isso requer a exclusão das 0-0600 de segunda e 1800 de fechamento na sexta-feira. O código permitia o rodízio do tempo, mas não por dias. Melhoramento:
    /*++++ Day/Time allowed to open*/{
    datetime    now = TimeGMT();
    //extern double   TradeHr.UTC.Start   =   7.3;    // London-1
    //extern double   TradeHr.UTC.End     =  12.9;    // NY open
    int secStart    = 3600*TradeHr.UTC.Start,
        secEnd      = 3600*TradeHr.UTC.End,
        hrBeg       = (now-secStart+86400)%86400,
        hrEnd       = (now-secEnd  +86400)%86400;
    if (hrBeg > hrEnd){ double Tminus=hrBeg/3600.-24;
                StrApnd(EA.status," HR", DoubleToStr(Tminus,2));    return; }
    // TradeHr: 0600-1800       1800-0600       1800-0600
    // TOD:     0600-1800       1800-2359       0000-0600
    // DOW:     DOW(today)      DOW(today)      DOW(yesterday)
    int         TOD = now % 86400;      // Time of the day
    datetime    BOD = now - TOD;        // Beginning of the day (today 0000z)
    if (TOD < secStart) int DOW = TimeDayOfWeek(BOD - 1);       // Yesterday.
    else                    DOW = TimeDayOfWeek(BOD),   /* https://www.mql5.com/en/forum/127483
            // reports DayOfWeek() always returns 5 in the tester. No refresh?*/
        int DayMask = 1 << DOW; // #define DAYS_MAX    0x3F// 1<<6-1=63. (S-F)
    //extern int      Days.Mask               =  55;      // Not Wed
    if ((Days.Mask & DayMask) == 0){  StrApnd(EA.status," Day=",DOW); return; }
    /*---- Day/Time allowed to open*/}
E minha correção para o comentário do RaptorUK:
double  PointValuePerLot(string pair="") {
    /* Value in acnSum currency of a Point of Symbol.
     * In tester I had a sale: open=1.35883 close=1.35736 (0.00147)
     * gain$=97.32/6.62 lots/147 points=$0.10/point or $1.00/pip.
     * IBFX demo/mini       EURUSD TICKVALUE=0.1 MAXLOT=50 LOTSIZE=10,000
     * IBFX demo/standard   EURUSD TICKVALUE=1.0 MAXLOT=50 LOTSIZE=100,000
     *                                  $1.00/point or $10.00/pip.
     *
     * https://www.mql5.com/en/forum/127584 CB: MODE_TICKSIZE will usually return the
     * same value as MODE_POINT (or Point for the current symbol), however, an
     * example of where to use MODE_TICKSIZE would be as part of a ratio with
     * MODE_TICKVALUE when performing money management calculations which need
     * to take acnSum of the pair and the acnSum currency. The reason I use
     * this ratio is that although TV and TS may constantly be returned as
     * something like 7.00 and 0.00001 respectively, I've seen this
     * (intermittently) change to 14.00 and 0.00002 respectively (just example
     * tick values to illustrate). */
    if (pair == "") pair = Symbol();
    return(  MarketInfo(pair, MODE_TICKVALUE)
           / MarketInfo(pair, MODE_TICKSIZE) ); // Not Point.
}
 
WHRoeder:
E minha correção pelo comentário do RaptorUK:
Eu renomeei PointValuePerLot para DeltaValuePerLot desde aCurrencyChange = aPriceChange * OrderSize() * DeltaValuePerLot(). Também acrescentei mais comentários.
double  PipValuePerLot(string pair=""){ return(DeltaValuePerLot() * pips2dbl); }
double  DeltaValuePerLot(string pair=""){
    /* Value in account currency of a Point of Symbol.
     * In tester I had a sale: open=1.35883 close=1.35736 (0.0147)
     * gain$=97.32/6.62 lots/147 points=$0.10/point or $1.00/pip.
     * IBFX demo/mini       EURUSD TICKVALUE=0.1 MAXLOT=50 LOTSIZE=10,000
     * IBFX demo/standard   EURUSD TICKVALUE=1.0 MAXLOT=50 LOTSIZE=100,000
     *                                  $1.00/point or $10.0/pip.
     *
     * https://www.mql5.com/en/forum/127584 CB: MODE_TICKSIZE will usually return the
     * same value as MODE_POINT (or Point for the current symbol), however, an
     * example of where to use MODE_TICKSIZE would be as part of a ratio with
     * MODE_TICKVALUE when performing money management calculations which need
     * to take account of the pair and the account currency. The reason I use
     * this ratio is that although TV and TS may constantly be returned as
     * something like 7.00 and 0.0001 respectively, I've seen this
     * (intermittently) change to 14.00 and 0.0002 respectively (just example
     * tick values to illustrate).
     * https://www.mql5.com/en/forum/135345 zzuegg reports for non-currency DE30:
     * MarketInfo(Symbol(),MODE_TICKSIZE) returns 0.5
     * MarketInfo(Symbol(),MODE_DIGITS) return 1
     * Point = 0.1
     * Prices to open must be a multiple of ticksize */
    if (pair == "") pair = Symbol();
    return(  MarketInfo(pair, MODE_TICKVALUE)
           / MarketInfo(pair, MODE_TICKSIZE) ); // Not Point.
}
 
double  PipValuePerLot(string pair=""){ return(DeltaValuePerLot(pair) * pips2dbl); }
 
Modifiquei o código Polyline para permitir sobreposições, por exemplo
double  bottom      =         WindowPriceMin(),
        top         = MathMax(WindowPriceMax(), bottom+pips2dbl),// Div0
        topQuarter  = (3*top +   bottom)/4.,
        botQuarter  = (top   + 3*bottom)/4.;
int     iVisible    =           WindowFirstVisibleBar(),
        iVisEnd     = MathMaxI( iVisible-WindowBarsPerChart(),0);// Shft
static bool drawOnTop = false;
if      (Bid >= topQuarter) drawOnTop = false;  // Hysteresis - previous
else if (Bid <= botQuarter) drawOnTop = true;   // location otherwise.
if (drawOnTop)  bottom  = topQuarter;
else            top     = botQuarter;
for(iWpr = MathMinI(iWprBegin, iVisible); iWpr >= iVisEnd; iWpr--)
    Polyline( WPR_NAME, wprValue[iWpr], Color.Wpr, iWpr,
              0., 100., bottom, top );
Compatível com as versões anteriores:
void TLine( string name, datetime T0, double P0, datetime T1, double P1,
            color clr, double V0=INF, double V1=INF, bool ray=false){
    if (!Show.Objects)  return;                         #define WINDOW_MAIN 0
    if      (ObjectMove( name, 0, T0, P0 ))     ObjectMove(name, 1, T1, P1);
    else if (!ObjectCreate( name, OBJ_TREND, WINDOW_MAIN, T0, P0, T1, P1 ))
        Alert("ObjectCreate(",name,",TREND) failed: ", GetLastError() );
    else if (!ObjectSet( name, OBJPROP_RAY, ray ))
        Alert("ObjectSet(", name, ",Ray) failed: ", GetLastError());
    if (!ObjectSet(name, OBJPROP_COLOR, clr )) // Allow color change
        Alert("ObjectSet(", name, ",Color) [2] failed: ", GetLastError());
    if (V0 == INF || V0 == P0){
        string  P0t = PriceToStr(P0);           if (MathAbs(P0 - P1) >= Point)
                P0t = StringConcatenate(P0t, " to ", PriceToStr(P1));       }
    else if (V0 == V1)  P0t = StringConcatenate(V0,""); // Suppress trailing to
    else                P0t = StringConcatenate(V0, " to ", V1);
    if (!ObjectSetText(name, P0t, 10))
        Alert("ObjectSetText(",name,") [2] failed: ", GetLastError());
}
 
//+------------------------------------------------------------------+
//| EA equivalent of indicator buffers                               |
//+------------------------------------------------------------------+
/*  Example 1:
 *  if (...) Ordermodify(...);
 *  Polyline("SL"+(oo.ticket%99), oo.SL, Color.SL, 0);
 *
 *  Example 2:
 *  double  ELineCurr = iMA(NULL,0, ELine.Period, 0, MODE_EMA, PRICE_CLOSE, 1);
 *  string pln=Polyline("ELine", ELineCurr, Color.ELine, 1);
 *      ObjectSet(pln, OBJPROP_STYLE, STYLE_DOT);
 *      ObjectSetText(pln, "ELine="+DoubleToStr(ELineCurr,Digits), 10);
 ******************************************************************************/
#define POLYLINE_MAX 30 // Must match valueXX[]
string  lineName[POLYLINE_MAX]; // Common to Polyline/PolylineDelete and helper.
string  Polyline(string name, double value, color clr, int shift=0,
    double indiMin=INF, double indiMax=INF, double chrtMin=INF, double chrtMax=INF){
    if (!Show.Objects)  return("");         // Return the actual object name for
    static int           LRU[POLYLINE_MAX]; // further modifications, E.G. style
    for (int iLine=0; iLine < POLYLINE_MAX; iLine++){
        bool isNew = lineName[iLine] != name;   if (!isNew) break;  }
    if (isNew){
        for (iLine=0; iLine < POLYLINE_MAX; iLine++)  LRU[iLine]++;
        iLine=ArrayMaximum(LRU);  lineName[iLine]=name;
    }
    LRU[iLine] = 0;
    double  value00[], value01[], value02[], value03[], value04[],
            value05[], value06[], value07[], value08[], value09[],
            value10[], value11[], value12[], value13[], value14[],
            value15[], value16[], value17[], value18[], value19[],
            value20[], value21[], value22[], value23[], value24[],
            value25[], value26[], value27[], value28[], value29[];
    switch (iLine){
    case  0: return(PLHelper(value00, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case  1: return(PLHelper(value01, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case  2: return(PLHelper(value02, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case  3: return(PLHelper(value03, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case  4: return(PLHelper(value04, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case  5: return(PLHelper(value05, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case  6: return(PLHelper(value06, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case  7: return(PLHelper(value07, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case  8: return(PLHelper(value08, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case  9: return(PLHelper(value09, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 10: return(PLHelper(value10, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 11: return(PLHelper(value11, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 12: return(PLHelper(value12, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 13: return(PLHelper(value13, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 14: return(PLHelper(value14, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 15: return(PLHelper(value15, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 16: return(PLHelper(value16, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 17: return(PLHelper(value17, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 18: return(PLHelper(value18, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 19: return(PLHelper(value19, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 20: return(PLHelper(value20, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 21: return(PLHelper(value21, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 22: return(PLHelper(value22, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 23: return(PLHelper(value23, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 24: return(PLHelper(value24, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 25: return(PLHelper(value25, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 26: return(PLHelper(value26, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 27: return(PLHelper(value27, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 28: return(PLHelper(value28, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    case 29: return(PLHelper(value29, value, clr, iLine, isNew, shift,
                                        indiMin, indiMax, chrtMin, chrtMax));
    }
    /*NOTREACHED*/
}   // Polyline
string  PLHelper( double& mem[],    double value0,  color clr,      int iLine,
                  bool isNew,       int shift,      double indiMin,
                  double indiMax,   double chrtMin, double chrtMax ){
    string name = lineName[iLine];
    double  price0  = value0;                               if (indiMin < INF){
        if (chrtMin == INF) chrtMin = WindowPriceMin();
        if (chrtMax == INF) chrtMax = WindowPriceMax();
            price0  = (value0 - indiMin) / (indiMax - indiMin)
                    * (chrtMax - chrtMin) + chrtMin;                        }
    datetime    t0  = Time[shift];  static datetime timeL[POLYLINE_MAX];
    if (!isNew){
        if (timeL[iLine] < Time[shift+1]){      // Missing bar(s), leave a gap.
            isNew = true;                                                   }
        else if (Time[shift] < timeL[iLine]){   // Redrawing earlier bars.
            isNew = true;
            for(int iObj=ObjectsTotal()-1; iObj >= 0; iObj--){
                string on = ObjectName(iObj);
                if (StringFind(on, name) == 0)  ObjectDelete(on);
    }   }   }
    if (isNew){
        if (!ResizeBuffer(mem, 2))  return("");
        mem[1]        = price0;     static datetime timeF[POLYLINE_MAX];
        timeF[iLine]  = t0;         static color    clrLn[POLYLINE_MAX];
        clrLn[iLine]  = clr;        static int      segNo[POLYLINE_MAX];
        segNo[iLine]++;                                                     }
    else if (clrLn[iLine] != clr){  ArrayResize(mem, 2);    // Series==true;
        mem[1]        = mem[0];
        timeF[iLine]  = timeL[iLine];
        clrLn[iLine]  = clr;
        segNo[iLine]++;                                                     }
    else if (timeL[iLine] < t0){                    // New bar, remember point
        if (!ResizeBuffer(mem, ArraySize(mem)+1))               return(""); }
    mem[0]          = price0;   timeL[iLine]    = t0;
    int     iFirst  = ArraySize(mem)-1;
    double  priceF  = mem[iFirst],
            valueF  = priceF;                               if (indiMin < INF){
            valueF  = (priceF - chrtMin) / (chrtMax - chrtMin)
                    * (indiMax - indiMin) + indiMin;                        }
    datetime Tf = timeF[iLine];                                 // One bar wide
    if (t0 == Tf)   Tf += IfI(-1, +1, shift==0)*60*Period();    // to be visual
    string  objName = name+"_"+RJust(segNo[iLine],3);
    TLine(objName, Tf, priceF, t0, price0, clr, valueF, value0);
    double maxError=0;  for (int iMem=1; iMem < iFirst; iMem++){
        double  hight   = ObjectGetValueByShift(objName, iMem+shift),
                error   = MathAbs(hight - mem[iMem]);
        if (error > maxError){  maxError = error;   int iMaxError = iMem; }
    }
    if (maxError >= pips2dbl){  // Split the line into two segments at max.
        double  priceM  = mem[iMaxError],
                valueM  = priceM;                           if (indiMin < INF){
                valueM  = (priceM - chrtMin) / (chrtMax - chrtMin)
                        * (indiMax - indiMin) + indiMin;    }
        TLine(objName,  timeF[iLine],           priceF,
                        Time[iMaxError+shift],  priceM, clr, valueF, valueM);
        ArrayResize(mem, iMaxError+1);          // Drop iFirst..(iMaxError+1)
        timeF[iLine] = Time[iMaxError+shift];
        segNo[iLine]++; objName=name+"_"+RJust(segNo[iLine], 3);
        TLine(objName, timeF[iLine], priceM, t0, price0, clr, valueM, value0);
    }   // Split the line into two segments at the max.
    return(objName);
}   // PLHelper
 
WHRoeder:
Modifiquei o código Polyline para permitir sobreposições, ...
TLne compatível com versões anteriores:
A partir de um post sobre o desenho do indicador tanto no gráfico principal quanto no sub gráfico, TLine poderia ser usado para ambos com modificações.
void TLine(string name, datetime T0, double P0, datetime T1, double P1,
           color clr, double V0=INF, double V1=INF, bool ray=false, int iWin=0){    
    if (!Show.Objects)  return;                         #define WINDOW_MAIN 0
    if      (ObjectMove( name, 0, T0, P0 ))     ObjectMove(name, 1, T1, P1);
    else if (!ObjectCreate( name, OBJ_TREND, iWin, T0, P0, T1, P1 ))
        Alert("ObjectCreate(",name,",TREND) failed: ", GetLastError() );
    else if (!ObjectSet( name, OBJPROP_RAY, ray ))
        Alert("ObjectSet(", name, ",Ray) failed: ", GetLastError());
    if (!ObjectSet(name, OBJPROP_COLOR, clr )) // Allow color change
        Alert("ObjectSet(", name, ",Color) [4] failed: ", GetLastError());
    if (V0 != INF)  // V0, V1 is used for non-price indicator overlayed on chart
        if (MathAbs( (V0 - V1) / MathMax(V0, V1) ) < 0.001)             string
                P0t = StringConcatenate(V0,"");
        else    P0t = StringConcatenate(V0, " to ", V1);
    else if (iWin != WINDOW_MAIN)
        if (MathAbs( (P0 - P1) / MathMax(P0, P1) ) < 0.001)
                P0t = StringConcatenate(P0,"");
        else    P0t = StringConcatenate(P0, " to ", P1);
    else if (MathAbs(P0 - P1) < Point_2)
                P0t = PriceToStr(P0);
    else        P0t = StringConcatenate(PriceToStr(P0), " to ", PriceToStr(P1));
    if (!ObjectSetText(name, P0t, 10))
        Alert("ObjectSetText(",name,") [1] failed: ", GetLastError());
}
Para desenhar no sub gráfico basta usar iWin = WindowFind("indicadorNome");
 
WHRoeder:
A partir de um post sobre o desenho do indicador tanto no gráfico principal quanto no sub gráfico, o TLine poderia ser usado para ambos com modificações.
Para desenhar na subcarta basta usar iWin = WindowFind("indicadorNome");

Obrigado
 

Horário de fechamento do mercado.

Eu queria fechar todas as ordens antes do final da semana (o mercado fecha na sexta-feira,) para evitar perdas caso a lacuna do mercado acabasse no final da semana, passando o SL. (Isto não é modelado no testador).

Portanto, a questão é quando o mercado fecha (ou abre.) Todos os lançamentos e buscas na rede estão claramente errados . Da Educação Forex - Introdução ao Forex - O mercado Forex IBFX opera 24 horas por dia, 5,5 dias por semana (18h00 ET no domingo até 16h00 ET na sexta-feira) É ET - horário local de Nova Iorque.

Isto significa que todos os lançamentos dependem de quando foram feitos, pois os limites do DST variam de ano para ano.

Isto significa que é necessário calcular quando o DST de NY começa e termina, para a barra em questão. (Para os testes posteriores, precisamos de valores até 2000, pelo menos.) O problema é que o Windows não fornece rotinas de conversão, exceto entre o TZ atual e o UTC e somente para o ano atual. Se o PC não estiver no ET, não pode ser feito diretamente. Além disso, até que o Windows8 saia, não é possível obter conversões para ET e anos anteriores. E olhando para o Registro no Win7 os valores só cobrem 2005 em (e estes estavam errados se eu os li corretamente.) Portanto, não estou apostando que o Win8 será melhor.

Isto significa que é necessário calcular eu mesmo o DST. Eu atualizei meu código: TimeGmt() e LocalTimeGMT() com argumentos padrão, alguma documentação adicional, e cheques, e escrevi o código para computar a hora de fechamento do mercado. Aproveite.

#define HR2400          86400                   // 24 * 3600
datetime TimeOfDay(datetime when){  return( when % HR2400          );       }
datetime DateOfDay(datetime when){  return( when - TimeOfDay(when) );       }
datetime    now.srv,    now.utc,    mkt.closes.srv;
:
    now.srv = TimeCurrent();
    now.utc = TimeGMT(now.srv);                 // May update Srvr.To.UTC.Hours
    if (now.srv > mkt.closes.srv){              // Compute next market close
        // Market closes Friday 4PM ET (NY local time) and opens Sunday 6PM ET.
        // That's either 2100z or 2000z depending on DST.
        // 18:00 Friday   in America/New_York
        // 12:00 Friday   in Pacific/Honolulu
        // 08:00 Saturday in Australia/Melbourne
        // 07:00 Saturday in Asia/Tokyo
        #define DOW_FRIDAY  5
        #define HR2100      75600   // 21 * 3600
        #define NY_TZ      -18000   // -5 * 3600 UTC-5 (STD) or UTC-4 (DST)
        datetime mktClosesUTC   = DateOfDay(now.utc)
                                + HR2400*(DOW_FRIDAY - TimeDayOfWeek(now.utc))
                                + HR2100;
        if (IsNYonDST(mktClosesUTC + NY_TZ))    mktClosesUTC -= 3600;   // UTC-4
        mkt.closes.srv = TimeServer(mktClosesUTC);
    }                                           // Compute next market close
:
//+------------------------------------------------------------------+
//| GMT Time                                                         |
//+------------------------------------------------------------------+
datetime TimeGMT(datetime serverTime=0){            // Server time to GMT time.
    if (serverTime == 0)    serverTime = TimeCurrent();
    static datetime nextAutoUpdate;     if (serverTime >= nextAutoUpdate){
        nextAutoUpdate = serverTime + 7200;
        if (Srvr.To.UTC.Auto
        )if(IsDllsAllowed()){                               // Complained @ init
            int     srvrToUTC       = LocalTimeGMT() - TimeCurrent();
            double  nearestHalfHour = MathRound(srvrToUTC / 1800.);
            Srvr.To.UTC.Hours       = nearestHalfHour / 2.; // Update external
    }   }
    return (serverTime + Srvr.To.UTC.Hours*3600.);
}
datetime TimeServer(datetime gmtTime){              // Server time to GMT time.
    return (gmtTime - Srvr.To.UTC.Hours*3600.);
}
#import "kernel32.dll"
int  GetTimeZoneInformation(int& TZInfoArray[]);
#import
datetime LocalTimeGMT(){    // TimeLocal to GMT forum.mql4.com/12057#522900
    // This is called only by TimeGMT. Check for IsDLLsAllowed() done there.
    int TZInfoArray[43];
    int tz  = GetTimeZoneInformation(TZInfoArray);
    int GMTshift    = TZInfoArray[0];   // GetTimeZoneInformation will return
    #define TIME_ZONE_ID_DAYLIGHT 2     // the right Bias even when it returns
    #define TIME_ZONE_ID_UNKNOWN  0     // UNKNOWN
    if (tz == TIME_ZONE_ID_DAYLIGHT || tz == TIME_ZONE_ID_UNKNOWN)
        GMTshift += TZInfoArray[42];
    return (TimeLocal() + GMTshift*60);
/*
 *  msdn.microsoft.com/en-us/library/windows/desktop/ms724421%28v=vs.85%29.aspx
 *  typedef struct _TIME_ZONE_INFORMATION {     typedef struct _SYSTEMTIME {
 *  LONG       Bias;              [ 0]  (min)   WORD wYear;         [0]
 *  WCHAR      StandardName[32];  [ 1]          WORD wMonth;            Jan=1
 *  SYSTEMTIME StandardDate;      [17]          WORD wDayOfWeek;    [1] Sun=1
 *  LONG       StandardBias;      [21]          WORD wDay;
 *  WCHAR      DaylightName[32];  [22]          WORD wHour;         [2]
 *  SYSTEMTIME DaylightDate;      [38]          WORD wMinute;
 *  LONG       DaylightBias;      [42]          WORD wSecond;       [3]
 *                                    }         WORD wMilliseconds;        }
 */
}
bool IsNYonDST(datetime whenNY){
    // Market opens Sunday 6PM ET (NY local time) and closes Friday 4PM ET.
    // DST changes at 2AM Sunday, when the market is closed. I don't have to
    // worry about the passed time here, only the date.
    int year    = TimeYear(     whenNY);                   #define MARCH     3
    int mon     = TimeMonth(    whenNY);                   #define APRIL     4
    int dom     = TimeDay(      whenNY);                   #define OCTOBER  10
    int dow     = TimeDayOfWeek(whenNY);                   #define NOVEMBER 11
    // http://en.wikipedia.org/wiki/Daylight_saving_time_in_the_United_States
    //                                      #History_of_DST_in_the_United_States
    // 1986-2006    DST the first Sunday in April to the last Sunday in October
    // 2007 on              second Sunday March         first Sunday in November
    if (year < 2007){ int   monBeg=APRIL,   secndSun=0,  monEnd=OCTOBER;    }
    else{                   monBeg=MARCH;   secndSun=7;  monEnd=NOVEMBER;   }
    if (mon < monBeg                     )  return(false);  // Early spring.
    if (                     mon > monEnd)  return(false);  // Late fall.
    if (mon != monBeg){ if (mon != monEnd)  return(true);   // Summer.
        if (year < 2007){   // Find last Sun = dom - (dow-SUNDAY) but SUNDAY==0
            for (int lastSun = dom-dow; lastSun+7 <= 31; lastSun += 7){}
            return (dom < lastSun);                         // DST Before Sun. &
    }   }                                                   // not on markt open
    // Otherwise first or second Sunday of MonBegin or first Sunday of MonEnd
    for (int firstSun = dom + 7-dow; firstSun > 7; firstSun--){}
    if (mon == monBeg)  return (firstSun+secndSun <= dom);  // DST On/After
    return (dom < firstSun);                                // DST Before Sun.
}
 
WHRoeder: correção.
    // Otherwise first or second Sunday of MonBegin or first Sunday of MonEnd
//  for (int firstSun = dom + 7-dow; firstSun > 7; firstSun--){}
    for (int firstSun = dom + 7-dow; firstSun > 7; firstSun -= 7){}
 

Estes são bons pontos, há muito mais coisas que são um trabalho de adivinhação mesmo com funções MT4, que nem sempre retornam o valor correto. Por exemplo, broker e serverinfo no servidor e parâmetros de negociação, como spread variável, ECN ou não, SL requerido ou não, resulta apenas do manuseio de erros, informações de símbolos, etc.

Muitos deles são simplesmente coisas básicas que não podem ser (e devem ser) facilmente verificadas. Por exemplo, informações sobre gráficos abertos e dados de histórico, informações de horário (como GMT, fuso horário, DST), informações de mercado aberto, informações de fechamento.

A recuperação de desastres seria realmente boa, começando com o MT4 não desligando e reiniciando como ele quer (atualizar), também o terminal.exe desligamento adequado, que permanece congelado no gerenciador de tarefas mesmo horas depois que o terminal foi fechado (e pensado para ser fechado corretamente com botão de fechamento sem qualquer mensagem de erro).

Algum tipo de suporte local de datacenter também seria bom, facilitaria o trabalho em vez de limitar variáveis globais e abrir arquivos. Para não mencionar o armazenamento de dados de pedido, lance, (spread), tick data que está faltando.

Há muitas coisas simples que faltam e que tornam a vida em conjunto muito mais difícil, e é uma quantidade horrível de trabalho para lidar com elas corretamente, se possível. Muitas dicas e truques externos são necessários até mesmo para uma operação adequada e extensa. Eu não culpo ninguém que publica uma estratégia na base de código e não lida com todos os problemas possíveis (muitos deles específicos do corretor) com o MT4 ou o servidor - especialmente quando a questão é sobre a estratégia e não sobre o tratamento de erros.

Mesmo coisas muito simples estão faltando, não podemos lidar com arquivos de log que podem facilmente crescer centenas de megabytes ou maiores quando algo realmente dá errado. Eles crescem até que o disco esteja cheio e nada pode ser feito, nem mesmo uma opção nas configurações do terminal no manuseio de arquivos de log.

Razão: