코드 기반에 Complete EA가 없는 이유는 무엇입니까? - 페이지 3

 
WHRoeder :
여기 내 에서 실제 거래 논리를 뺀 값이 있습니다.
나는 거래 시간/일 필터에 관해 PM을 받았습니다. 요청은 월요일-금요일 1800-0600이었습니다. 이를 위해서는 월요일 0-0600, 금요일 1800-종료를 제외해야 합니다. 코드는 시간 롤오버를 허용하지만 며칠 동안은 허용하지 않습니다. 상승:
     /*++++ 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의 의견 에 대한 수정 사항:
aCurrencyChange = aPriceChange * OrderSize() * DeltaValuePerLot() 이후 PointValuePerLot의 이름을 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 :
오버레이를 허용하도록 Polyline 코드를 수정했습니다.
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 교육에서 - Forex 소개 - IBFX Forex 시장은 주 5.5일, 하루 24시간 운영됩니다(일요일 오후 6시 ET부터 금요일 오후 4시 ET까지) . 바로 ET - 뉴욕 현지 시간입니다.

이는 DST 경계가 해마다 다르기 때문에 모든 게시가 작성된 시기에 따라 다르다는 것을 의미합니다.

이는 해당 막대에 대해 NY DST가 시작되고 끝나는 시간을 계산해야 함을 의미합니다. (백 테스트를 위해서는 최소한 2000의 값이 필요합니다.) 문제는 Windows가 현재 TZ와 UTC 사이를 제외하고는 현재 연도에 대해서만 변환 루틴을 제공하지 않는다는 것입니다. PC가 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), 시장 개장, 마감 정보에 대한 정보입니다.

재해 복구는 MT4가 종료되지 않고 원하는 대로 다시 시작하는 것(업데이트), 터미널이 닫힌 것보다 몇 시간이 지나도 작업 관리자에서 고정된 상태로 유지되는 terminal.exe 적절한 종료로 시작하여 정말 좋습니다. 오류 메시지 없이 닫기 버튼으로 올바르게).

어떤 종류의 로컬 데이터 센터 지원도 좋을 것이며 제한된 전역 변수와 열린 파일 대신 작업을 더 쉽게 만들 것입니다. 누락된 물음, 입찰, (확산) 틱 데이터의 저장은 말할 것도 없습니다.

함께 삶을 훨씬 더 어렵게 만드는 간단한 누락된 것들이 많이 있으며, 가능하면 올바르게 처리하는 데 엄청난 노력이 필요합니다. 광범위한 적절한 작동을 위해서는 많은 외부 팁과 트릭이 필요합니다. 코드베이스에 전략을 게시하고 MT4 또는 서버에서 발생할 수 있는 모든 문제(대부분 브로커 관련 문제)를 처리하지 않는 사람을 비난하지 않습니다. 특히 오류 처리가 아닌 전략에 요점이 있을 때 그렇습니다.

아주 간단한 것조차 빠져 있습니다. 무언가 정말 잘못되면 수백 메가바이트 이상으로 쉽게 커질 수 있는 로그 파일을 처리할 수 없습니다. 디스크가 가득 차서 아무 것도 할 수 없을 때까지 증가합니다. 로그 파일 처리에 대한 터미널 설정의 옵션도 마찬가지입니다.