¿Por qué NO hay un EA completo en la base de código? - página 3

 
WHRoeder:
Aquí está el mío menos la lógica de comercio real.
Tuve un PM en relación con el filtro de hora/día de negociación. La solicitud era de 1800-0600 de lunes a viernes. Eso requiere excluir 0-0600 lunes y 1800-cierre el viernes. El código permitía la renovación de la hora pero no de los días. Mejora:
    /*++++ 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*/}
Y mi corrección para el comentario de 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:
Y mi corrección para el comentario de RaptorUK:
He cambiado el nombre de PointValuePerLot por DeltaValuePerLot ya que aCurrencyChange = aPriceChange * OrderSize() * DeltaValuePerLot(). También he añadido más comentarios.
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); }
 
He modificado el código de la polilínea para permitir las superposiciones, por ejemplo:
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 );
Compatible con el pasado:
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:
He modificado el código de Polyline para permitir superposiciones, ..
TLne Compatible con la versión anterior:
A partir de un post sobre el dibujo de indicadores tanto en el gráfico principal como en el subgráfico, TLine podría utilizarse para ambos con modificaciones.
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 dibujar en el subgráfico sólo hay que utilizar iWin = WindowFind("indicatorName");
 
WHRoeder:
De un post sobre el dibujo de indicadores tanto en el gráfico principal como en el subgráfico, TLine podría ser utilizado para ambos con modificaciones.
Para dibujar en el gráfico secundario sólo tiene que utilizar iWin = WindowFind("indicatorName");

Gracias
 

Hora de cierre del mercado.

Quería cerrar todas las órdenes antes del final de la semana (cierre del mercado el viernes,) para evitar pérdidas en caso de que el mercado se desviara sobre el final de la semana, pasando el SL. (Esto no está modelado en el probador).

Así que la pregunta es cuándo se cierra (o se abre) el mercado. Todas las publicaciones y búsquedas en la red son simplemente erróneas. De Forex Education - Introduction to Forex - IBFX El mercado de divisas opera 24 horas al día, 5,5 días a la semana (6:00 PM ET el domingo hasta las 4:00 PM ET el viernes) Eso es ET - hora local de Nueva York.

Esto significa que todas las contabilizaciones dependen del momento en que se hayan realizado, ya que el límite del horario de verano varía de un año a otro.

Esto significa que es necesario calcular cuando empieza y termina el DST de NY, para la barra en cuestión. (El problema es que Windows no proporciona rutinas de conversión, excepto entre la TZ actual y la UTC, y sólo para el año en curso. Si el PC no está en ET no se puede hacer directamente. Es más, hasta que no salga Windows8 no se pueden conseguir conversiones para ET y años anteriores. Y mirando el Registro en Win7 los valores solo cubren el 2005 en adelante (y esos eran erróneos si leí bien.) Así que no apuesto a que Win8 sea mejor.

Esto significa que es necesario calcular el DST yo mismo. He actualizado mi código: TimeGmt() y LocalTimeGMT() con argumentos por defecto, algo de documentación adicional y comprobaciones, y he escrito código para calcular la hora de cierre del mercado. Que lo disfruten.

#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: corrección.
    // 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){}
 

Estos son buenos puntos, hay muchas más cosas que son una conjetura incluso con las funciones de MT4, que no siempre devuelven el valor correcto. Por ejemplo broker y serverinfo en el servidor y los parámetros de negociación, como la propagación variable, ECN o no, SL requerido o no resulta sólo de la gestión de errores, información de símbolos, etc.

Muchos de ellos son simplemente cosas básicas que no pueden ser (y deberían ser) fácilmente comprobadas. Por ejemplo, la información sobre los gráficos abiertos y los datos del historial, la información de la hora (como GMT, zona horaria, DST), la información de apertura y cierre del mercado.

La recuperación de desastres sería realmente buena, comenzando con que MT4 no se apague y se reinicie como quiere (actualización), también el cierre correcto de terminal.exe, que permanece congelado en el administrador de tareas incluso horas después de que el terminal se cerró (y se pensó que se cerró correctamente con el botón de cierre sin ningún mensaje de error).

Algún tipo de soporte de centro de datos local también sería bueno, haría el trabajo más fácil en lugar de variables globales limitadas y archivos abiertos. Por no mencionar el almacenamiento de los datos de compra, venta y ticks (spread), que faltan.

Hay muchas cosas simples que faltan que hacen la vida mucho más difícil juntos, y es una cantidad de trabajo horrible para manejarlos correctamente si es posible. Muchos consejos externos nad trucos incluso hacks son necesarios para un amplio funcionamiento adecuado. No culpo a nadie que publique una estrategia en codebase y no maneje todos los posibles (muchos de ellos específicos del broker) problemas con MT4 o el servidor - especialmente cuando el punto está en la estrategia no en el manejo de errores.

Incluso faltan cosas muy simples, no podemos manejar los archivos de registro que pueden crecer fácilmente cientos de megabytes o más cuando algo va realmente mal. Crecen hasta que el disco está lleno y no se puede hacer nada, ni siquiera una opción en la configuración del terminal sobre el manejo de los archivos de registro.