
Visual Testing of the Profitability of Indicators and Alerts
What indicator of trading alerts or just the methods of their calculating to use is usually decided when testing EAs using these alerts. However, it is not always possible/necessary/reasonable to write an EA for each indicator. You can promptly calculate the profitability of trading on the alerts from other indicators, using a special indicator that collects their alerts itself and draws a picture of ideal trading with them. It can help you both make a visual estimate of the results obtained and quickly choose most optimal parameters.
Remember how many times, looking at a randomly found or long time searched for and finally found indicator, you wanted to know immediately what the result of trading by its alerts would be. The same situation occurs when you are offered a new trading system for which there are no EAs or indicators yet. Before starting a serious work and writing a working EA, you would like to estimate whether there is a healthy grain in the materials on offer.
Or you can have the following situation: There is an indicator with good alerts, but you are having a gut feeling that its parameters are not optimal, that you can clear it up, and you even know how you can do that. How can you test your idea quickly without being locked into a long and complicated coding?
Problem Statement
Let's think of what we have and what we want to have. Let's take a well-known ZigZag from the standard delivery of MetaTrader 4 as an example. Attach it to any currency pair's chart on any timeframe: Do you really want to trade with it? Everything is clear: you should sell on the upper kink and close your position by buying on the lower one.
Now here is a question: How much money would this trading gain for you? It is quite easy to get an answer to this question: Sum up all highs of the segments and recalculate considering the volume of the position in lots and the price of one point in the deposit currency. You can access to the buffer of ZigZag values by calling for function iCustom:
P=iCustom(NULL,0,"ZigZag",0,i);
where i is the number of the bar for which you're going to obtain a value.
All you have to do now is to search in all values of the buffer and find all points with nonzero values - these are the points to build the ZigZag on. Well, you also have to sum up the heights of the segments. For descriptive reasons, you can even draw those lines and color them according to the colors of trades and their profitability. This task is quite easy and can be successfully assigned to an indicator.
A Universal Solution
Fur such indicator to be able to test any other indicator, you should ensure its universality. Since any indicator or trading system, in a general case, assumes that only 4 operations are made: BUY, SELL, BUY CLOSE, and SELL CLOSE, we should have a special array for each of them. It must be possible to fill this array from any source. It is the only thing you have to edit yourself by adding the code of filling alerts arrays (well, you should probably place some parameters in external variables, too).
Functionally, the indicator consists of the following blocks:
- Initialization - here we allocate the memory for alerts arrays and reset the counters;
- Filling alerts arrays - here we are going to edit the code by adding various algorithms of calculating alerts or of receiving them from other indicators;
- Clearing repeated alerts -this block is necessary for "thinning" the alerts from indicators that don't work in a discrete mode that generates one alert, but in a continuous one where the indicator continuously fixes the availability of opening conditions, not the very first appearance of the alert by which, actually, the order must be opened. In the block, the following mechanism is realized: If two identical alerts are located in neighboring bars, the right one is rest, since we consider only one order for being used, which has already been opened at the preceding (left) bar. All alerts outside the dates range set in the parameters are removed here, too;
- Placing OPEN and CLOSE marks - in this block, the ZigZag is drawn by the "thinned" (discrete) alerts, vertical lines are placed, if necessary, to track the synchronization of alerts with the charts of other indicators including those producing the alerts;
- Calculating results by the marks placed - the amounts of open orders and their profits are calculated in the course of placing marks. This block makes some additional calculations and shows their results as a comment in the main chart window;
- Help functions - two functions are located here: that of placing vertical marking lines and that of drawing the segments of ZigZag.
Realization
Below is the code of the indicator itself, which contains an example of feeding the data from indicator ZigZag.
/*///——————————————————————————————————————————————————————————————————————————————————————————————————————— IndicatorTester.mq4 Visual Testing the Profitability of Indicators and Alerts Copyright © 2006, Кравчук Сергей, http://forextools.com.ua /*///——————————————————————————————————————————————————————————————————————————————————————————————————————— #property copyright "Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua" #property link "http://forextools.com.ua" #property indicator_chart_window #property indicator_buffers 0 // parameters for displaying the elements of the chart extern bool ShowZZ = true; // should the ZZ be drawn? extern bool ShowMARKERS = true; // should the vertical marking lines be drawn? //dates of drawing the chart extern datetime DateStart = D'1.01.1970'; extern datetime DateEnd = D'31.12.2037'; //parameters of profit calculations extern double LotForCalc = 0.05; // the amount of lots for profit calculations extern int Optimizm = 0; // -1 gives a pessimistic calculation; 0 gives the calculation on bar opening prices; //+1 is optimistic // BUY lines colors extern color ColorProfitBuy = Blue; // line color for profitable BUY trades extern color ColorLossBuy = Red; // line color for losing BUY trades extern color ColorZeroBuy = Gray; // line color for BUY trades with zero profits // SELL lines colors extern color ColorProfitSell = Blue; // line color for profitable SELL trades extern color ColorLossSell = Red; // line color for losing SELL trades extern color ColorZeroSell = Gray; // line color for SELL trades with zero profits // alert lines colors extern color ColorBuy = CornflowerBlue; // line color for BUY alerts extern color ColorSell = HotPink; // line color for SELL alerts extern color ColorClose = Gainsboro; // line color for closing alerts //—————————————————————————————————————————————————————————————————————————————————————————————————————————— double sBuy[],sCloseBuy[],sSell[],sCloseSell[]; // arrays for alerts int sBuyCnt,sSellCnt,sBuyCloseCnt,sSellCloseCnt;// alerts counters int i,DisplayBars; //—————————————————————————————————————————————————————————————————————————————————————————————————————————— // service codes #define MrakerPrefix "IT_" #define OP_CLOSE_BUY 444 #define OP_CLOSE_SELL 555 //—————————————————————————————————————————————————————————————————————————————————————————————————————————— int init() { ClearMarkers(); return(0); } int deinit() { ClearMarkers(); return(0); } //—————————————————————————————————————————————————————————————————————————————————————————————————————————— int start() { double Profit=0,P1,P2; int CntProfit=0,CntLoose=0,i1,i2; //———————————————————————————————————————————————————————————————————————————————————————————————————————— // delete all marks, in case the indicator is going to be redrawn ClearMarkers(); //———————————————————————————————————————————————————————————————————————————————————————————————————————— // prepare alerts counters sBuyCnt=0; sSellCnt=0; sBuyCloseCnt=0; sSellCloseCnt=0; //———————————————————————————————————————————————————————————————————————————————————————————————————————— // allocate some memory for alerts arrays and zeroize their valuesя DisplayBars=Bars; // the amount of bars to be displayed ArrayResize(sBuy,DisplayBars); ArrayInitialize(sBuy,0); ArrayResize(sSell,DisplayBars); ArrayInitialize(sSell,0); ArrayResize(sCloseBuy,DisplayBars); ArrayInitialize(sCloseBuy,0); ArrayResize(sCloseSell,DisplayBars); ArrayInitialize(sCloseSell,0); //———————————————————————————————————————————————————————————————————————————————————————————————————————— // find the first point and save its location and price for(i1=Bars-1;i1>=0;i1--) { P1=iCustom(NULL,0,"ZigZag",0,i1); if(P1!=0) break; } // process the ZigZag points for(i2=i1-1;i2>=0;i2--) { // find the next point and save its location and price for(i2=i2;i2>=0;i2--) { P2=iCustom(NULL,0,"ZigZag",0,i2); if(P2!=0) break; } if(i2<0) break; // place the last point on the current price // the opening conditions are at the same time the conditions of closing an opposite order if(P1>P2) { sSell[i1]=1; sBuy[i2]=1; sCloseSell[i2]=1; } if(P1<P2) { sBuy[i1]=1; sSell[i2]=1; sCloseBuy[i2]=1; } P1=P2; i1=i2; // save the bar in which the point has been found } //—————————————————————————————————————————————————————————————————————————————————————————————————————— // delete the repeated alerts having saved only the very first ones located to the left on the chart for(i=0;i<DisplayBars;i++) { if(sBuy[i]==sBuy[i+1]) sBuy[i]=0; if(sSell[i]==sSell[i+1]) sSell[i]=0; if(sCloseBuy[i]==sCloseBuy[i+1]) sCloseBuy[i]=0; if(sCloseSell[i]==sCloseSell[i+1]) sCloseSell[i]=0; } // delete the alerts outside the specified range of dates for(i=0;i<DisplayBars;i++) { if(Time[i]<DateStart || DateEnd<Time[i]) { sBuy[i]=0; sSell[i]=0; sCloseBuy[i]=0; sCloseSell[i]=0; } } // add forcible closing marginal positions if(DateEnd<=Time[0]) { i=iBarShift(Symbol(),Period(),DateEnd); sBuy[i]=0; sSell[i]=0; sCloseBuy[i]=1; sCloseSell[i]=1; } if(DateEnd >Time[0]) { sCloseBuy[0]=1; sCloseSell[0]=1; } //———————————————————————————————————————————————————————————————————————————————————————————————————————— // count the amount of alerts for(i=0;i<DisplayBars;i++) { if(sBuy [i]!=0) sBuyCnt++; if(sCloseBuy [i]!=0) sBuyCloseCnt++; if(sSell[i]!=0) sSellCnt++; if(sCloseSell[i]!=0) sSellCloseCnt++; } //———————————————————————————————————————————————————————————————————————————————————————————————————————— // place the marks, draw a ZZ and calculate the profits //———————————————————————————————————————————————————————————————————————————————————————————————————————— // process BUY trades for(i=DisplayBars-1;i>=0;i--) // go and collect the points { // find the next OPEN point and save its location and price for(i1=i;i1>=0;i1--) if(sBuy[i1]!=0) break; // find the next CLOSE point of a BUY trade and save its location and price for(i2=i1-1;i2>=0;i2--) if(sCloseBuy[i2]!=0) break; if(i2<0) i2=0; // for the last unclosed position, calculate the CLOSE on the current price i=i2; // new bar to continue searching for OPEN points // define the prices for drawing according to the parameter of optimism, Optimizm if(Optimizm<0) { P1=High[i1]; P2=Low[i2]; } if(Optimizm==0) { P1=Open[i1]; P2=Open[i2]; } if(Optimizm>0) { P1=Low[i1]; P2=High[i2]; } P1/=Point; P2/=Point; // express prices in points // find the profit and fill out the corresponding buffer if(i1>=0) { Profit=Profit+P2-P1; // collect the summed profit if(P2-P1>=0) CntProfit++; else CntLoose++; // count the number of orders DrawLine(i1,i2,OP_BUY,Optimizm); // draw the order line PlaceMarker(i1,OP_BUY); PlaceMarker(i2,OP_CLOSE_BUY); } } //———————————————————————————————————————————————————————————————————————————————————————————————————————— // process the SELL trades for(i=DisplayBars-1;i>=0;i--) // go and collect the points { // find the next OPEN point and save its location and price for(i1=i;i1>=0;i1--) if(sSell[i1]!=0) break; // find the next CLOSE point of a SELL trade and save its location and price for(i2=i1-1;i2>=0;i2--) if(sCloseSell[i2]!=0) break; if(i2<0) i2=0; // for the last unclosed position, calculate the CLOSE on the current price i=i2; // new bar to continue searching for OPEN points // define the prices for drawing according to the parameter of optimism, Optimizm if(Optimizm<0) { P1=Low[i1]; P2=High[i2]; } if(Optimizm==0) { P1=Open[i1]; P2=Open[i2]; } if(Optimizm>0) { P1=High[i1]; P2=Low[i2]; } P1/=Point; P2/=Point; // express prices in points // if there are both points available, find the profit and fill the corresponding buffer if(i1>=0) { Profit=Profit+P1-P2; // collect the summed profit if(P1-P2>=0) CntProfit++; else CntLoose++; // count the number of orders DrawLine(i1,i2,OP_SELL,Optimizm); // draw the order line PlaceMarker(i1,OP_SELL); PlaceMarker(i2,OP_CLOSE_SELL); } } //———————————————————————————————————————————————————————————————————————————————————————————————————————— // calculating the totals for commenting int Cnt=CntProfit+CntLoose; // total number of operations // coefficient to transfer points into the deposit currency double ToCurrency = MarketInfo(Symbol(),MODE_TICKVALUE)*LotForCalc; string msg="Период: "+TimeToStr(MathMax(DateStart,Time[Bars-1]))+" - " + TimeToStr(MathMin(DateEnd,Time[0]))+"\n\n"; msg=msg+ sBuyCnt+" BUY trades and "+sBuyCloseCnt+" their closings\n"+ sSellCnt+" SELL trades and "+sSellCloseCnt+" their closings\n\n"; // total time in days int TotalDays = (MathMin(DateEnd,Time[0])-MathMax(DateStart,Time[Bars-1]))/60/60/24; //translate seconds into days if(TotalDays<=0) TotalDays=1; // to avoid zero divide for shorter days if(Cnt==0) msg=msg+("No operations"); else msg=msg+ ( DoubleToStr(Profit,0)+" point on "+Cnt+" operations for "+TotalDays+" days\n"+ DoubleToStr(Profit/Cnt,1)+" point for operation ("+ DoubleToStr(Profit/TotalDays,1)+" within a day)\n\n"+ "When trading with "+DoubleToStr(LotForCalc,2)+" obtain in "+AccountCurrency()+":\n"+ DoubleToStr(Profit*ToCurrency,0)+" totally, by "+ DoubleToStr(Profit/Cnt*ToCurrency,1)+" per trade ("+ DoubleToStr(Profit/TotalDays*ToCurrency,1)+" within one day)\n\n"+ CntProfit+" profitable ("+DoubleToStr(((CntProfit)*1.0/Cnt*1.0)*100.0,1)+"%)\n"+ CntLoose+" losing ("+DoubleToStr(((CntLoose)*1.0/Cnt*1.0)*100.0,1)+"%)" ); Comment(msg); } //—————————————————————————————————————————————————————————————————————————————————————————————————————————— //—————————————————————————————————————————————————————————————————————————————————————————————————————————— // deleting all objects from our chart void ClearMarkers() { for(int i=0;i<ObjectsTotal();i++) if(StringFind(ObjectName(i),MrakerPrefix)==0) { ObjectDelete(ObjectName(i)); i--; } } //—————————————————————————————————————————————————————————————————————————————————————————————————————————— // placing a vertical line - marks of the operation of the op_type type void PlaceMarker(int i, int op_type) { if(!ShowMARKERS) return; // displaying markers disabled color MarkerColor; string MarkName; // __ for the CLOSE line to be drawn below the OPEN line at sorting if(op_type==OP_CLOSE_SELL) { MarkerColor=ColorClose; MarkName=MrakerPrefix+"__SELL_"+i; } if(op_type==OP_CLOSE_BUY) { MarkerColor=ColorClose; MarkName=MrakerPrefix+"__BUY_"+i; } if(op_type==OP_SELL) { MarkerColor=ColorSell; MarkName=MrakerPrefix+"_SELL_"+i; } if(op_type==OP_BUY) { MarkerColor=ColorBuy; MarkName=MrakerPrefix+"_BUY_"+i; } ObjectCreate(MarkName,OBJ_VLINE,0,Time[i],0); ObjectSet(MarkName,OBJPROP_WIDTH,1); if(op_type==OP_CLOSE_BUY || op_type==OP_CLOSE_SELL) ObjectSet(MarkName,OBJPROP_STYLE,STYLE_SOLID); else ObjectSet(MarkName,OBJPROP_STYLE,STYLE_DOT); ObjectSet(MarkName,OBJPROP_BACK,True); ObjectSet(MarkName,OBJPROP_COLOR,MarkerColor); } //—————————————————————————————————————————————————————————————————————————————————————————————————————————— // placing a line on the chart for the operation of the op_type type at the prices of parameter Optimizm void DrawLine(int i1,int i2, int op_type, int Optimizm) { if(!ShowZZ) return; // ZZ displaying disabled color СurColor; string MarkName=MrakerPrefix+"_"+i1+"_"+i2; double P1,P2; // define prices for drawing, according to parameter Optimizm if(Optimizm<0 && op_type==OP_BUY) { P1=High[i1]; P2=Low[i2]; } if(Optimizm<0 && op_type==OP_SELL) { P1=Low[i1]; P2=High[i2]; } if(Optimizm==0) { P1=Open[i1]; P2=Open[i2]; } if(Optimizm>0 && op_type==OP_BUY) { P1=Low[i1]; P2=High[i2]; } if(Optimizm>0 && op_type==OP_SELL) { P1=High[i1]; P2=Low[i2]; } ObjectCreate(MarkName,OBJ_TREND,0,Time[i1],P1,Time[i2],P2); ObjectSet(MarkName,OBJPROP_RAY,False); // draw segments, not lines ObjectSet(MarkName,OBJPROP_BACK,False); ObjectSet(MarkName,OBJPROP_STYLE,STYLE_SOLID); ObjectSet(MarkName,OBJPROP_WIDTH,2); // set line color depending on the profitability of the trade if(op_type==OP_BUY) { if(P1 <P2) СurColor = ColorProfitBuy; if(P1==P2) СurColor = ColorZeroBuy; if(P1 >P2) СurColor = ColorLossBuy; } if(op_type==OP_SELL) { if(P1 >P2) СurColor = ColorProfitSell; if(P1==P2) СurColor = ColorZeroSell; if(P1 <P2) СurColor = ColorLossSell; } ObjectSet(MarkName,OBJPROP_COLOR,СurColor); } //——————————————————————————————————————————————————————————————————————————————————————————————————————————The parameters of the indicator contain a special parameter, Optimizm. It sets the desired degree of optimism in calculations. If its value is below zero, it means that the calculations will be fully pessimistic: for BUY prices it will choose the High of the alert bar, for SELL prices - Low. This is how the worst possible results are modeled that we can obtain by those alerts. If its value is above zero, the most optimistic calculation is modeled: buying at lowest and selling at highest. If the value of this parameter is equal to zero, the neutral behavior is formed at which we open and close orders at the OPEN prices of bars - it is this situation that is usually realized when trading with EAs.
Analyzing Results
Now let's see results. Here is the result obtained at the objective analysis of zigzag.
See, the chart shows eight losing parts. Well, the zigzag "works" on best prices and in order to reconstruct it again we should set the parameter Optimizm = 1.
What the result will be, if we trade as badly as possible, can be seen if we set the parameter Optimizm = -1
A Little Digression
Dear traders,
Do not put a blame on me, but this indicator can be a pretty lash for you if it occurs in your management's skillful hands, who are usually not interested in details of trading tactics - they are interested only in the result. Uploading into a tester the algorithm of ZigZag alerts and setting Optimizm = 1, they will obtain the figures of that maximal profit that could ever be obtained from this part of chart and that they would like you to obtain. And if you always trade less than a half, this will make them think that you might be too indifferent to your duties.
On the other hand this tool can be a good defense from unfairly steep demands. You will have ground arguments that plans set to you by them are unreal and cannot be obtained even at the most favorable conditions.
We see, the use of the single Optimizm parameter allows to use the indicator for the potential estimation of an indicator of alerts tested in it. And even if the most optimistic calculation does not make profit, the tested indicator of alerts should be amended: you should find other parameters for it or in the worst case forget it for its hopelessness saving time on EA development and money of your deposit that could be lost for getting proofs that the indicator does not work. Thus our testing indicator allows saving not only time, but also money.
Analyzing Alerts of Trading Systems
Buffers of other indicators are not the only source for filling out alert arrays, on which our testing indicator operates. Somewhere in books or in the Internet depths you can find description of alerts of a trading system, for which there are no indicators or Expert Advisors. This is just a set of rules that can though be easily implemented in MQL4. If you can write the calculation of alerts for such a system and fill out alert buffers by them, the testing indicator will show you results that you can obtain using the system.
If there is a ready code for a system, you can select calculation of alerts, on which the EA operates, and construct "results of its operation" directly on the chart. Of course the same can be obtained even more precisely in MetaTrader 4 strategy tester, but the indicator will perform reconstructions quicker and reflect them more vividly than strict lines of a tester.
An important moment in this case is the possibility to join the chart of obtained results with other indicators. Vertical mark lines crossing additional indicators perhaps will tell you how they can be used for specifying main alerts or will detect places of its inadequate operation. Finally only by the hit-and-miss method we can choose such parameters of values that probably would suit us more than results of optimizer.
Let us take as an example the ready code of the standard MACD. This is how it should look like. Block of filling alert arrays, the contents of which are copied and pasted from the indicator text:
// fill out alert arrays with values and count them for(i=DisplayBars;i>=0;i--) { double MacdCurrent, MacdPrevious, SignalCurrent; double SignalPrevious, MaCurrent, MaPrevious; // to simplify the coding and speed up access // data are put into internal variables MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+0); MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+1); SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+0); SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+1); MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+0); MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+1); // check for long position (BUY) possibility if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious) sBuy[i]=1; // check for short position (SELL) possibility if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent<MaPrevious) sSell[i]=1; if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseBuy[i]=1; if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseSell[i]=1; }
And here is the result:
Note that lines of alert marks fully match with crosspoints of MACD charts. Perhaps looking at these joint charts you will decide what exactly should be changed in alerts. For example that MaCurrent and MaPrevious do not need checking. A little corrected code:
// fill out alert arrays with values and count them for(i=DisplayBars;i>=0;i--) { double MacdCurrent, MacdPrevious, SignalCurrent; double SignalPrevious, MaCurrent, MaPrevious; // to simplify the coding and speed up access // data are put into internal variables MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+0); MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+1); SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+0); SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+1); MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+0); MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+1); // check for long position (BUY) possibility if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point)) sBuy[i]=1; // check for short position (SELL) possibility if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point)) sSell[i]=1; if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseBuy[i]=1; if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseSell[i]=1; }
You see what the result is. The number of operations has increased from 19 to 51. Though the total profit has turned into losses, which shows that this was not a good idea of improving the alert quality.
Testing Fantasies
Each developer surely has some intrusive thoughts that are never handled. The tester of indicators will help to quickly visualize and estimate them. If ideas appear to be correct and obtained results are positive, a developer can think of writing an indicator or Expert Advisor. In this case results of the indicator tester will be at the same time an illustration to the requirements specification for development and a final example, according to which the ready product will be checked.
Here is a primitive "system" as an example: buy using simple MA indicator. Buy condition - MA grows, sell condition - MA falls. See, how to quickly check the profitability of this idea. Here is the block of alert filling:
// fill out alert arrays with values and count them for(i=DisplayBars;i>=0;i--) { double m1=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+1); double m2=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+2); // open conditions are at the same time close conditions of an opposite order if(m2<=m1 && MathAbs(m1-m2)>0.2*Point) { sBuy[i]=1; sCloseSell[i]=1; sBuyCnt++; sSellCloseCnt++; } if(m2>=m1 && MathAbs(m1-m2)>0.2*Point) { sSell[i]=1; sCloseBuy[i]=1; sSellCnt++; sBuyCloseCnt++; } }
And here are results:
Not bad, but it is not the best result - because we have fancied incredible profits. Now let's try to diminish MA period to increase the possibility of winning on profit trades. Diminishing the period from 15 to 7 bars, we managed to increase the average daily profit almost twice:
What is left is making the correlation of profitable and losing trades equal to at least 80% to 20%. But you will have to do it without my assistance.
Conclusion
Now you have one more tool for express analysis of indicators and trading alerts. Naturally they do not substitute for the tester or real trading. All data obtained using this tool are of a descriptive, estimation character. However, the convenience of operation, visualization and the speed of obtained results let me believe that this tool may be very useful to any developer. It helps to quickly check trading ideas, not wasting much time and effort. To a certain extent it can be a proof of an idea's being promising or hopeless. And a thinking investigator or experimentalist this can be a tool of delicate optimization of indicator parameters.
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/1557





- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
thanks for the article but still not sure how to program still .. could you do me a favour of writing an alert indicator combining two charts like CCI (14, 6) and stochastic oscillator together so that when the signals and the bases are crossed, they give signal of sound ???
thanks :D
It solves a problem I've been working at, with only partial success.
One question - which part(s) of the code need changing if one uses a different indicator?
This obviously does:
// find the first point and save its location and price
for(i1=Bars-1;i1>=0;i1--) { P1=iCustom(NULL,0,"ZigZag",0,i1); if(P1!=0) break; }
// process the ZigZag points
for(i2=i1-1;i2>=0;i2--)
{
// find the next point and save its location and price
for(i2=i2;i2>=0;i2--) { P2=iCustom(NULL,0,"ZigZag",0,i2); if(P2!=0) break; }
if(i2<0) break; // place the last point on the current price
// the opening conditions are at the same time the conditions of closing an opposite order
if(P1>P2) { sSell[i1]=1; sBuy[i2]=1; sCloseSell[i2]=1; }
if(P1<P2) { sBuy[i1]=1; sSell[i2]=1; sCloseBuy[i2]=1; }
P1=P2; i1=i2; // save the bar in which the point has been found
} // for(i2
Is that all?
Junja
Sergey -
This tool is by far the best tool EVER for evalauting trading strategies. I only use the Strategy Tester when I want to be frustrated! :)
I have some screenshots of non-redrawing indicators that are 80% and above - all facilitated by your code!
Thanks again,
http://arachnode.net
Thank you for this tool. It is very useful and is helping me to test ideas very rapidly,
like in a New York minute compared to the Strategy Tester which takes ages!
I recommend it.