MT4-LevelStop-Reverse-vB0-2





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

/////////////////////////////////////////////////////////////////////
// Version 0.2 Beta
//
// 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 beta version
//
/////////////////////////////////////////////////////////////////////

/*

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 -  The number of pips away from the high or low of the bar that
                   the arrow should display.

On the colors tab, only the first color is used. It is the color of the dotted
stop line.

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.

This is version Beta 0.2.  As I get feedback, I will release newer versions as needed.
*/


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

#property indicator_chart_window
#property indicator_buffers 5
#property indicator_color1 Magenta
#property indicator_style1 STYLE_DOT

#define INDICATOR_VERSION "vB0.2"


//---- input parameters

extern bool UseATRMode = true;
extern int NonATRStopPips = 40;
extern int ATRPeriod = 9;
extern double ATRMultiplier = 3.0;
extern int ATRSmoothing = 0;
extern color UpArrowColor = DodgerBlue;
extern color DnArrowColor = OrangeRed;
extern int ArrowDistance = 25;

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

//---- variables
int ArrowObjects[50];


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init() {
    string ShortName;
    
    int DrawBegin = 0;
    if ( UseATRMode ) {
        DrawBegin = ATRPeriod;
    }
    
    IndicatorBuffers( 5 );
    SetIndexStyle( 0, DRAW_LINE, STYLE_DOT, 1 );
    SetIndexBuffer( 0, TrStopLevel );
    SetIndexDrawBegin( 0, DrawBegin );
    
    SetIndexStyle( 1, DRAW_NONE );
    SetIndexBuffer( 1, UpSignal );
    SetIndexDrawBegin( 1, DrawBegin );
    
    SetIndexStyle( 2, DRAW_NONE );
    SetIndexBuffer( 2, DnSignal );
    SetIndexDrawBegin( 2, DrawBegin );

    SetIndexStyle( 3, DRAW_NONE );
    SetIndexBuffer( 3, ATRBuffer );
    SetIndexDrawBegin( 3, DrawBegin );

    SetIndexStyle( 4, DRAW_NONE );
    SetIndexBuffer( 4, SmoothBuffer );
    SetIndexDrawBegin( 4, DrawBegin );

    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" );
    
    for ( int ictr = 0; ictr < 50; ictr++ ) {
        ArrowObjects[ictr] = 0;
    }

    MathSrand( TimeLocal() );
    
    return( 0 );
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                         |
//+------------------------------------------------------------------+
int deinit() {
    int num_elems = ArraySize( ArrowObjects );
    Print( "deinit() - number of objects to delete: ", num_elems );
    for ( int ictr = 0; ictr < num_elems; ictr++ ) {
        if ( ArrowObjects[ ictr ] == 0 ) {
            Print( "ArrowObjects[", ictr, "] is zero" );
            break;
        }
        
        string ObjName = "VTS-" + ArrowObjects[ictr];
        ObjectDelete( ObjName );
    }
    return( 0 );
}



//+------------------------------------------------------------------+
//| Momentum                                                         |
//+------------------------------------------------------------------+
int start() {
    Comment( "\nMT4-LevelStop-Reverse Beta v0.2" );
    
    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 );
    }
    
    int xctr;
    
    if ( UseATRMode ) {
        // First calculate the ATR
        for ( xctr = 0; xctr < limit; xctr++ ) {
            ATRBuffer[xctr] = iATR( NULL, 0, ATRPeriod, xctr );
        }
            
        // Smooth the ATR if necessary
        if ( ATRSmoothing > 0 ) {
            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 ) {
            if ( ATRSmoothing > 0 ) {
                DeltaStop = NormalizeDouble( SmoothBuffer[xctr] * ATRMultiplier, 4 );
            }
            else {
                DeltaStop = NormalizeDouble( ATRBuffer[xctr] * ATRMultiplier, 4 );
            }
        }
        
        // Figure out where the current bar's stop level should be
        double NewStopLevel;
        double PrevStop = TrStopLevel[xctr + 1];
        
        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;
                    }
                    else {
                        NewStopLevel = Close[xctr] + DeltaStop;
                    }
                }
            }
        }
        
        TrStopLevel[xctr] = NewStopLevel;
        
        // Figure out the up/down arrows
        bool Up = false;
        bool Dn = false;
        
        if ( Close[xctr] > TrStopLevel[xctr] && Close[xctr + 1] <= TrStopLevel[xctr + 1] ) {
            Up = true;
            UpSignal[xctr] = Low[xctr] - ( ArrowDistance * Point );
            int next_ind = GetNextObjectIndex();
            int obj_id = MathRand() + 1;
            string ObjName = "VTS-" + obj_id;
            ObjectCreate( ObjName, OBJ_ARROW, 0, Time[xctr], UpSignal[xctr] );
            ObjectSet( ObjName, OBJPROP_COLOR, UpArrowColor );
            ObjectSet( ObjName, OBJPROP_ARROWCODE, 233 );
            ArrowObjects[next_ind] = obj_id;
        }
            
        if ( Close[xctr] < TrStopLevel[xctr] && Close[xctr + 1] >= TrStopLevel[xctr + 1] ) {
            Dn = true;
            DnSignal[xctr] = High[xctr] + ( ( ArrowDistance + 10 ) * Point );
            next_ind = GetNextObjectIndex();
            obj_id = MathRand() + 1;
            ObjName = "VTS-" + obj_id;
            ObjectCreate( ObjName, OBJ_ARROW, 0, Time[xctr], DnSignal[xctr] );
            ObjectSet( ObjName, OBJPROP_COLOR, DnArrowColor );
            ObjectSet( ObjName, OBJPROP_ARROWCODE, 234 );
            ArrowObjects[next_ind] = obj_id;
        }
        
        // Reverse TrStopLevel According to Up and Down Signals
        if ( Up ) {
            TrStopLevel[xctr] = Close[xctr] - DeltaStop;
        }
        else {
            if ( Dn ) {
                TrStopLevel[xctr] = Close[xctr] + DeltaStop;
            }
        }
    }
        
    return( 0 );
}


//+------------------------------------------------------------------+
//| Gets the next object index so they can be deleted later          |
//+------------------------------------------------------------------+
int GetNextObjectIndex() {
    int retval = 0;
    int arr_size = ArraySize( ArrowObjects );
    int max_elem = arr_size - 1;
    
    if ( ArrowObjects[max_elem] != 0 ) {
        // Resize the array
        ArrayResize( ArrowObjects, arr_size + 10 );
        for ( int xctr = arr_size; xctr < ( arr_size + 10 ); xctr++ ) {
            ArrowObjects[xctr] = 0;
        }
        retval = arr_size;
        arr_size += 10;
    }
    else {
        for ( int ictr = 0; ictr < arr_size; ictr++ ) {
            if ( ArrowObjects[ ictr ] == 0 ) {
                retval = ictr;
                break;
            }
        }
    }
    
    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 );
}
    


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



Sample





Analysis



Market Information Used:

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


Indicator Curves created:

Implements a curve of type DRAW_LINE

Implements a curve of type DRAW_NONE

Indicators Used:

Indicator of the average true range
Moving average indicator


Custom Indicators Used:

Order Management characteristics:

Other Features: