MT4_Reverse_Arrows





//+------------------------------------------------------------------+
//|                                            MT4-LevelStop-Reverse |
//|                                                      Version 2.0 |
//|                Copyright © 2007-2008, Bruce Hellstrom (brucehvn) |
//|                                              bhweb@speakeasy.net |
//|                                       http://www.metaquotes.net/ |
//+------------------------------------------------------------------+

/////////////////////////////////////////////////////////////////////
// Version 2.0
//
// This is a port of the VTTrader VT-LevelStop-Reverse trading system.
// This is ported as an MT4 indicator only and perhaps can be evolved
// into an EA later.
//
/////////////////////////////////////////////////////////////////////

/*

This is a combination of two VT Trader trading systems.  The first is the default
VT-LevelStop-Reverse and the second is one that was modified to allow customizing
the ATR settings for calculating the stop line.  I've tried to combine these 2
versions into a single MT4 indicator.

The default VT version allows you to use two modes, optimized, and manual.
Optimized mode calculates the stop line by using a 14 period EMA smoothed
ATR(14) multiplied by a fixed multiplier of 2.824. In manual mode, you set a
fixed number of pips you want the stop line to be drawn. In my MT4 version,
there are two modes:

1. ATR mode (customizable ATR period, multiplier, and smoothing)
2. Fixed stop mode (customizable fixed stop)

The input parameters are as follows:

* UseATRMode -     This calculates the stop line based on ATR using customizable period, multiplier and smoothing.
* NonATRStopPips - If "UseATRMode" is false, then this value is the number of fixed pips to place the stop line.
* ATRPeriod -      If "UseATRMode" is true, then this sets the ATR period.
* ATRMultiplier -  If "UseATRMode" is true, then the ATR value will be multiplied by this value when calculating the stop line.
* ATRSmoothing -   If "UseATRMode" is true, then this will smooth the selected ATR with an EMA of this smoothing period.
* UpArrowColor -   The color the Up arrows will display in.
* DnArrowColor -   The color the Down arrows will display in.
* ArrowDistance -  This can adjust the distance away from the stop line that the arrows appear. By default, the arrows appear directly above or below the stop line. A positive number here will move the arrows further away from the price.  A negative number will move it closer to the price.
* AlertSound -     If true, this will sound an alert when the reverse condition has been triggered.
* AlertMail -      If true, will send email to the email address registered with MT4.
* ShowComment - This will turn on/off the comment on the chart.  Turn off if you have other indicators that put data there and you don't want it overwritten.

For the default VT-LevelStop-Reverse behavior, set the following:
UseATRMode = true
ATRPeriod = 14
ATRMultiplier = 2.824
ATRSmoothing = 14

To use this indicator, copy it to your <MetaTrader Folder>\experts\indicators folder. Then restart MT4. It will appear in the custom indicators list.

Revision History

Version Beta 0.2
* Minor bug fixes.
* Remove extra "UseVTDefault" option.
* Add smoothing option for compatibility with default VT version.

Version Beta 0.3
* Delete objects at startup.
* Use a more unique object name prefix.
* Change ATRBuffer and SmoothBuffer to be non-indicator buffers.
* No need for UpSignal and DnSignal to be buffers.
* Change arrows to display at the stop line.
* Fix bug on current bar drawing that would cause multiple arrows to appear.

Version Beta 0.4
* Fix bug in non-indicator buffers that was causing erroneous data in the ATR buffer and smoothing buffer.

Version 1.0
* Fix some problems with the original VT formula that caused arrows to be drawn incorrectly if the price closed at the exact same level as the stop line.Fix bug in non-indicator buffers that was causing erroneous data in the ATR buffer and smoothing buffer.
* Add some print statements for arrow tracking.
* Always smooth, just use 1 for a value if no smoothing is indicated.
* Add ShowComment option

Version 2.0
* Fix multiple arrows being drawn in the same place.
* Try to fix an issue where arrows sometimes disappear.
* Add alerts.
* Name arrow objects incrementally rather than via random number.
*_____________________________________________________________________
* Settings for Timeframes
* 1. 1 min = 1.39
* 2. 5 min = 2.0
* 3. 15 min = 2.0
* 4. 1 hr = 0.51
* 5. 4 hr = 0.52
* 6. Daily = 0.33
* 7. Weekly = 0.58
*/

#property copyright "Copyright © 2007-2008, Bruce Hellstrom (brucehvn)"
#property link      "http: //www.metaquotes.net/"

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 Magenta
#property indicator_style1 STYLE_DOT
#property indicator_color2 Yellow
#property indicator_color3 Red
#property indicator_width2 5 
#property indicator_width3 5 

#define INDICATOR_VERSION "v2.0"
#define VTS_OBJECT_PREFIX "vtsbh2483-"


//---- input parameters

extern bool UseATRMode = true;
extern int NonATRStopPips = 40;
extern int ATRPeriod = 50;//was 9
extern double ATRMultiplier = 2.0;// was 2.45
extern int ATRSmoothing = 100;
extern color UpArrowColor = Yellow;
extern color DnArrowColor = Red;
extern int ArrowDistance = 0;
extern bool AlertSound = true;
extern bool AlertMail = false;
extern bool ShowComment = false;
double alertBar;


//---- buffers
double TrStopLevel[];
double UpSignal[];
double DnSignal[];

//---- variables
double ATRBuffer[];
double SmoothBuffer[];
string ShortName;
int ArrowObjects = 0;
int ArrowNumber;
int PrevArrows = 0;
datetime LastArrowTime = 0;
bool LastArrowSignal = 0;
datetime LastAlertBar = 0;
datetime CurrentBarTime = 0;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init() {

    int DrawBegin = 0;
    if ( UseATRMode ) {
        DrawBegin = ATRPeriod;
    }
    
    // Set the smoothing to 1 if it is zero or less
    if ( ATRSmoothing <= 0 ) {
        ATRSmoothing = 1;
    }
    
    IndicatorBuffers( 3 );
    SetIndexStyle( 0, DRAW_LINE, STYLE_DOT, 1 );
    SetIndexBuffer( 0, TrStopLevel );
    SetIndexDrawBegin( 0, DrawBegin );
    SetIndexStyle(1, DRAW_ARROW, STYLE_SOLID);
    SetIndexArrow(1, 221);
    SetIndexBuffer(1, UpSignal);
       SetIndexEmptyValue(1,0.0);
    SetIndexStyle(2, DRAW_ARROW, STYLE_SOLID);
    SetIndexArrow(2, 222);
    SetIndexBuffer(2, DnSignal);
       SetIndexEmptyValue(2,0.0);
    ShortName = "MT4-LevelStop-Reverse-" + INDICATOR_VERSION + "(";
    
    if ( UseATRMode ) {
        ShortName = StringConcatenate( ShortName, "ATRMode ", ATRPeriod, ", ",
                                       ATRMultiplier, ", ", ATRSmoothing, " )" );
    }
    else {
        ShortName = StringConcatenate( ShortName, "Manual Mode Stop = ", NonATRStopPips, " )" );
    }
    
    IndicatorShortName( ShortName );
    SetIndexLabel( 0, ShortName );
    
    Print( ShortName );
    Print( "Copyright (c) 2007 - Bruce Hellstrom, bhweb@speakeasy.net" );
    
    MathSrand( TimeLocal() );
    
    // Cleanup any leftover objects from previous runs
    DeleteAllArrowObjects();
    ArrowNumber = 0;
    ArrowObjects = 0;
    
    return( 0 );
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                         |
//+------------------------------------------------------------------+
int deinit() {
    DeleteAllArrowObjects();
    return( 0 );
}

//+------------------------------------------------------------------+
//| Function run on every tick                                       |
//+------------------------------------------------------------------+
int start() {
    
    int ictr;
    int counted_bars = IndicatorCounted();
    
    // Check for errors
    if ( counted_bars < 0 ) {
        return( -1 );
    }

    // Last bar will be recounted
    if ( counted_bars > 0 ) {
        counted_bars--;
    }
    
    int limit = Bars - counted_bars;
    ictr = limit - 1;
    
    if ( UseATRMode && Bars < ATRPeriod ) {
        return( 0 );
    }
    
    // Make sure buffers are sized correctly
    int buff_size = ArraySize( TrStopLevel );
    if ( ArraySize( ATRBuffer ) != buff_size ) {
        ArraySetAsSeries( ATRBuffer, false );
        ArrayResize( ATRBuffer, buff_size );
        ArraySetAsSeries( ATRBuffer, true );

        ArraySetAsSeries( SmoothBuffer, false );
        ArrayResize( SmoothBuffer, buff_size );
        ArraySetAsSeries( SmoothBuffer, true );
    }
    
    int xctr;
    
    if ( UseATRMode ) {
        // First calculate the ATR
        for ( xctr = 0; xctr < limit; xctr++ ) {
            ATRBuffer[xctr] = iATR( NULL, 0, ATRPeriod, xctr );
        }
            
        // Smooth the ATR
        for ( xctr = 0; xctr < limit; xctr++ ) {
            SmoothBuffer[xctr] = Wilders( ATRBuffer, ATRSmoothing, xctr );
        }
    }
    
    
    for ( xctr = ictr; xctr >= 0; xctr-- ) {
         // Calculate the stop amount
        double DeltaStop = NonATRStopPips * Point;
        
        // Calculate our stop value based on ATR if required
        if ( UseATRMode ) {
            DeltaStop = NormalizeDouble( SmoothBuffer[xctr] * ATRMultiplier, 4 );
        }
        
        // Figure out where the current bar's stop level should be
        double NewStopLevel;
        double PrevStop = TrStopLevel[xctr + 1];
        bool Up = false;
        bool Dn = false;
        
        if ( Close[xctr] == PrevStop ) {
            NewStopLevel = PrevStop;
        }
        else {
            if ( Close[xctr + 1] <= PrevStop && Close[xctr] < PrevStop ) {
                NewStopLevel = MathMin( PrevStop, ( Close[xctr] + DeltaStop ) );
            }
            else {
                if ( Close[xctr + 1] >= PrevStop && Close[xctr] > PrevStop ) {
                    NewStopLevel = MathMax( PrevStop, ( Close[xctr] - DeltaStop ) );
                }
                else {
                    if ( Close[xctr] > PrevStop ) {
                        NewStopLevel = Close[xctr] - DeltaStop;
                        Up = true;
                    }
                    else {
                        NewStopLevel = Close[xctr] + DeltaStop;
                        Dn = true;
                    }
                }
            }
        }
        
        
        TrStopLevel[xctr] = NewStopLevel;
        // Can't do the arrows until the bar closes
        if ( xctr > 0 ) {
            if ( Up ) { 
                if ( Time[xctr] > LastArrowTime ) {
                    UpSignal[xctr] = TrStopLevel[xctr] - ( ArrowDistance * Point );
                    string ObjName = GetNextObjectName();
                    ObjectCreate( ObjName, OBJ_ARROW, 0, Time[xctr], UpSignal );
                    ObjectSet( ObjName, OBJPROP_COLOR, UpArrowColor );
                    ObjectSet( ObjName, OBJPROP_ARROWCODE, 233 );
                    ArrowObjects++;
                    LastArrowTime = Time[xctr];
                    LastArrowSignal = true;
                }
            }
            
            if ( Dn ) {
                if ( Time[xctr] > LastArrowTime ) {
                    DnSignal[xctr] = TrStopLevel[xctr] + ( 2 * Point ) + ( ArrowDistance * Point );
                    ObjName = GetNextObjectName();
                    ObjectCreate( ObjName, OBJ_ARROW, 0, Time[xctr], DnSignal );
                    ObjectSet( ObjName, OBJPROP_COLOR, DnArrowColor );
                    ObjectSet( ObjName, OBJPROP_ARROWCODE, 234 );
                    ArrowObjects++;
                    LastArrowTime = Time[xctr];
                    LastArrowSignal = false;
                }
            }
        }
        
        // Do the alerting
        if ( xctr == 1 ) {
            if ( LastArrowTime == Time[xctr] ) {
                DoAlerts();
            }
        }
        
        // Check to see if we've closed a bar and redraw the objects
        if ( xctr == 0 ) {
            if ( Time[xctr] != CurrentBarTime ) {
                ObjectsRedraw();
                CurrentBarTime = Time[xctr];
            }
        }
                
    }
    
    if ( ArrowObjects != PrevArrows ) {
        Print( "Total Arrow Objects: ", ArrowObjects );
        PrevArrows = ArrowObjects;
    }
        
    return( 0 );
}


//+------------------------------------------------------------------+
//| Gets the next object index so they can be deleted later          |
//+------------------------------------------------------------------+
string GetNextObjectName() {
    //int rand_val = MathRand() + 1;
    ArrowNumber++;
    //string retval = VTS_OBJECT_PREFIX + rand_val;
    string retval = VTS_OBJECT_PREFIX + ArrowNumber;
    return( retval );
}
        

//+------------------------------------------------------------------+
//| Wilders Calculation                                              |
//+------------------------------------------------------------------+
double Wilders( double& indBuffer[], int Periods, int shift ) {
    double retval = 0.0;
    retval = iMAOnArray( indBuffer, 0, ( Periods * 2 ) - 1, 0, MODE_EMA, shift );
    return( retval );
}
    
//+------------------------------------------------------------------+
//| Delete all the arrow objects                                     |
//+------------------------------------------------------------------+
void DeleteAllArrowObjects() {
    int delcnt = 0;
    for ( int ictr = 1; ictr <= ArrowNumber; ictr++ ) {
        string ObjName = VTS_OBJECT_PREFIX + ( ictr + 1 );
        if ( ObjectDelete( ObjName ) ) {
            delcnt++;
        }
    }
    Print( "Objects deleted: ", delcnt );
    return;
}

//+------------------------------------------------------------------+
//| Handles alerting via sound/email                                 |
//+------------------------------------------------------------------+
void DoAlerts() {
    if ( LastArrowTime > LastAlertBar ) {
   
        if ( AlertSound) {
            int per = Period();
            string perstr = "";
            
            switch( per ) {
                case PERIOD_M1:
                    perstr = "M1";
                    break;
                    
                case PERIOD_M5:
                    perstr = "M5";
                    break;
                    
                case PERIOD_M15:
                    perstr = "M15";
                    break;
                    
                case PERIOD_M30:
                    perstr = "M30";
                    break;
                    
                case PERIOD_H1:
                    perstr = "H1";
                    break;
                    
                case PERIOD_H4:
                    perstr = "H4";
                    break;
                    
                case PERIOD_D1:
                    perstr = "D1";
                    break;
                    
                case PERIOD_W1:
                    perstr = "W1";
                    break;
                    
                case PERIOD_MN1:
                    perstr = "MN1";
                    break;
                    
                default:
                    perstr = "" + per + " Min";
                    break;
            }
                    
            datetime curtime = TimeCurrent();
            string strSignal = "LONG";
            if ( !LastArrowSignal && Bars>alertBar) {
                strSignal = "SHORT";
            }
            string str_subject = "MT4 - ";
            Alert ( str_subject,
                      "StopLevelReverse " +
                      strSignal +
                      " signal on " +
                      Symbol() +
                      " " + perstr + "." );
        }
        
        LastAlertBar = LastArrowTime;alertBar = Bars;

//email Alert

        if ( AlertMail) {
            int per1 = Period();
            string perstr1 = "";
            
            switch( per1 ) {
                case PERIOD_M1:
                    perstr1 = "M1";
                    break;
                    
                case PERIOD_M5:
                    perstr1 = "M5";
                    break;
                    
                case PERIOD_M15:
                    perstr1 = "M15";
                    break;
                    
                case PERIOD_M30:
                    perstr1 = "M30";
                    break;
                    
                case PERIOD_H1:
                    perstr1 = "H1";
                    break;
                    
                case PERIOD_H4:
                    perstr1 = "H4";
                    break;
                    
                case PERIOD_D1:
                    perstr1 = "D1";
                    break;
                    
                case PERIOD_W1:
                    perstr1 = "W1";
                    break;
                    
                case PERIOD_MN1:
                    perstr1 = "MN1";
                    break;
                    
                default:
                    perstr1 = "" + per1 + " Min";
                    break;
            }
                    
            datetime curtime1 = TimeCurrent();
            string strSignal1 = "LONG";
            if ( !LastArrowSignal && Bars>alertBar) {
                strSignal = "SHORT";
            }
            string str_subject1 = "MT4 - ";
            SendMail ( str_subject,
                      "StopLevelReverse " +
                      strSignal1 +
                      " signal on " +
                      Symbol() +
                      " " + perstr1 + "." );
        }
        
        LastAlertBar = LastArrowTime;alertBar = Bars;
    }
// finish email alert   
}
    

//+------------------------------------------------------------------+



Sample





Analysis



Market Information Used:

Series array that contains close prices for each bar
Series array that contains open time of each bar


Indicator Curves created:

Implements a curve of type DRAW_LINE

Implements a curve of type DRAW_ARROW

Indicators Used:

Indicator of the average true range
Moving average indicator


Custom Indicators Used:

Order Management characteristics:

Other Features: