为什么代码库中没有完整的EA? - 页 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:
我修改了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来防止损失。(这一点在测试器中没有被模拟出来。)

所以问题是市场何时收盘(或开盘)。网上所有 的帖子和搜索都是 错误的。 外汇教育--外汇简介--IBFX 外汇市场每天24小时,每周5.5天(美国东部时间周日下午6:00至美国东部时间周五下午4:00)运作,这是美国东部时间--纽约当地时间。

这意味着所有的 发布都取决于他们的时间,因为夏令时的边界每年都不一样。

这意味着有必要计算出纽约夏令时的开始和结束时间,对于有关的酒吧。(问题是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),市场开盘、收盘信息。

灾难恢复将是非常好的,从MT4不关闭和重新启动开始(更新),还有终端.exe的正确关闭,甚至在终端关闭后的几个小时内仍冻结在任务管理器中(被认为是用关闭按钮正确关闭,没有任何错误信息)。

某种本地数据中心的支持也很好,这将使工作更容易,而不是有限的全局变量和打开的文件。更不用说储存卖出价、买入价、(价差)tick的数据了,这些数据都没有。

有许多简单的缺失的东西使生活变得更加困难,如果可能的话,要正确处理它们是一个非常大的工作量。 许多外部技巧和窍门,甚至黑客都需要广泛的正确操作。 我不怪任何人在代码库上发布策略而不处理MT4或服务器上所有可能的(其中许多是经纪人特有的)问题--特别是当重点放在策略上而不是错误处理时。

即使是非常简单的东西也没有,我们不能处理日志文件,当事情真的出错时,日志文件可以很容易地增长到几百兆甚至更大。它们一直增长到磁盘满了,而我们却无能为力,甚至不能在终端设置中选择对日志文件的处理。