Почему в кодовой базе нет полного эксперта? - страница 3

 
WHRoeder:
Вот мой вариант за вычетом собственно торговой логики.
Я получил сообщение в PM относительно фильтра торгового времени/дня. Запрос был 1800-0600 понедельник-пятница. Это требует исключения 0-0600 в понедельник и 1800-close в пятницу. Код позволял переносить время, но не дни. Усовершенствование:
    /*++++ 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*/}
И моя поправка к комментарию 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:
И моя поправка к комментарию RaptorUK:
Я переименовал PointValuePerLot в DeltaValuePerLot, поскольку aCurrencyChange = aPriceChange * OrderSize() * DeltaValuePerLot(). Также добавлены дополнительные комментарии.
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); }
 
Я изменил код Polyline, чтобы разрешить наложения, например:
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 );
Обратная совместимость:
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:
Я изменил код полилинии, чтобы разрешить наложения, ...
Обратная совместимость TLne:
Из сообщения о рисовании индикатора как на основном графике, так и на субграфике, TLine может быть использован для обоих с модификациями.
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());
}
Для рисования на субграфике просто используйте iWin = WindowFind("indicatorName");
 
WHRoeder:
Из сообщения о рисовании индикатора как на основном графике, так и на субграфике, TLine может быть использован для обоих с изменениями.
Для рисования на субграфике просто используйте iWin = WindowFind("indicatorName");

Спасибо
 

Время закрытия рынка.

Я хотел закрыть все ордера до конца недели (рынок закрывается в пятницу), чтобы предотвратить потери, если рынок разойдется в конце недели, пройдя SL. (Это не смоделировано в тестере).

Итак, вопрос в том, когда закрывается (или открывается) рынок. Все сообщения и поиски в сети просто неверны. От Forex Education - Introduction to Forex - IBFX Рынок Forex работает 24 часа в сутки, 5,5 дней в неделю (6:00 PM ET в воскресенье до 4:00 PM ET в пятницу) Это ET - Нью-Йоркское местное время.

Это означает, что все проводки зависят от того, когда они были сделаны, так как граница DST меняется из года в год.

Это означает, что необходимо вычислить, когда начинается и заканчивается NY DST для рассматриваемого бара. (Для обратного тестирования нам нужны значения по крайней мере до 2000 г.) Проблема в том, что Windows не предоставляет процедур преобразования, кроме как между текущим TZ и UTC, и только для текущего года. Если ПК не находится в системе ET, это невозможно сделать напрямую. Более того, пока не выйдет Windows8, вы не сможете получить конвертацию для ET и предыдущих лет. А в реестре Win7 значения охватывают только 2005 год (и те были неверными, если я правильно их прочитал), так что я не думаю, что Win8 будет лучше.

Это означает, что необходимо самостоятельно вычислить DST. Я обновил свой код: TimeGmt() и LocalTimeGMT() с аргументами по умолчанию, некоторой дополнительной документацией и проверками, а также написал код для вычисления времени закрытия рынка. Наслаждайтесь.

#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: коррекция.
    // 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){}
 

Это хорошие моменты, есть еще много вещей, которые являются догадкой даже с функциями MT4, которые не всегда возвращают правильное значение. Например, информация о брокере и сервере и торговые параметры, такие как переменный спред, ECN или нет, SL требуется или нет, выясняется только из обработки ошибок, информации о символах и т.д.

Многие из них - просто базовые вещи, которые не могут быть (и не должны быть) легко проверены. Например, информация об открытых графиках и исторических данных, информация о времени (например, GMT, часовой пояс, DST), информация об открытии и закрытии рынка.

Disaster Recovery было бы действительно хорошо, начиная с того, что MT4 не выключается и перезапускается, как он хочет (обновление), также terminal.exe правильно выключается, который остается замороженным в диспетчере задач даже спустя несколько часов после того, как терминал был закрыт (и считалось, что он был закрыт правильно с помощью кнопки закрытия без какого-либо сообщения об ошибке).

Неплохо было бы сделать поддержку локального датацентра, это облегчило бы работу вместо ограниченных глобальных переменных и открытых файлов. Не говоря уже о хранении тиковых данных ask, bid, (spread), которые отсутствуют.

Есть много простых недостающих вещей, которые делают жизнь намного сложнее, и это ужасно много работы, чтобы обработать их правильно, если это возможно. Многие внешние советы и трюки, даже хаки, необходимы для обширной правильной работы. Я не виню никого, кто публикует стратегию на codebase и не обрабатывает все возможные (многие из них специфические для брокера) проблемы с MT4 или сервером - особенно когда суть в стратегии, а не в обработке ошибок.

Даже очень простые вещи отсутствуют, мы не можем работать с лог-файлами, которые могут легко вырасти в сотни мегабайт или больше, когда что-то идет не так. Они растут до тех пор, пока диск не заполняется, и ничего нельзя сделать, даже опции в настройках терминала по обработке лог-файлов.

Причина обращения: