วันอังคารที่ 21 พฤษภาคม พ.ศ. 2556

grid


/Three grades take profit Grid System, use it on weak market and fluctuating market, may need close all positions at some time.

//+------------------------------------------------------------------+
//|                                                     204060.mq4 |
//|                                                     Robbie Ruan  |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|History:                                                          
//|Ver 0.01 2009.08.01                                              
//|Ver 0.02 2012.02.18
//|   1. Modified CloseAllWithEquityIncrease's EquityIncreasePercentage Control                                                                                    
//+------------------------------------------------------------------+
#property copyright "Robbie Ruan ver0.02 2012.02.18"
#property link      "robbie.ruan@gmail.com"

string        GridName = "AIGrid";       // identifies the grid. allows for several co-existing grids
extern int    MagicNumberGrid = 10001;   // Magic number of the trades. must be unique to identify the trades of one grid                                                                              
extern double Lots = 0.01;              //
extern bool   ConsiderSpread = false;
extern double GridSize = 20;            // pips between orders - grid or mesh size
extern double BaseTakeProfit = 50;        // number of ticks to take profit. normally is = grid size but u can override
extern double Slippage = 2.5;
extern double GridSteps = 10;          // total number of orders to place
extern double GridMaxOpenEachSide = 0;         // maximum number of open positions either long or short side, not the sum of both
extern double StopLoss = 0;            // if u want to add a stop loss. normal grids dont use stop losses
extern double Grid_High = 0;           //define a regione that the price wave in
extern double Grid_Low = 0;            //
extern int    TrailStop = 0;

extern double FixedAllLongStopLoss = 0;     //All long orders use the same StopLoss
extern double FixedAllShortStopLoss = 0;    //All Short orders use the same StopLoss
extern double UpdateInterval = 0;      // update orders every x minutes

extern bool   wantLongs = true;        //  do we want long positions
extern bool   wantShorts = true;      //  do we want short positions
extern bool   wantBreakout = true;     // do we want longs above price, shorts below price
extern bool   wantCounter = true;      // do we want longs below price, shorts above price

extern bool   ProfitRank1 = true;        // Control Profit Rank, if ProfitRank2,3 both false, then it's equals to 20 program
extern bool   ProfitRank2 = false;
extern bool   ProfitRank3 = false;

extern bool   unEquLongShortControlLots = false;
extern bool   EquityControlLots = false;

extern double BaseLots = 0.01;
extern double BaseEquity = 2000;

double        Equity_Old;
extern bool   CloseAllWithEquityIncrease = false;
extern bool   CloseAllWithEquityDecrease = false;
extern double EquityIncreasePercentage = 10.0;
extern double EquityDecreasePercentage = 10.0;
extern string Note1 = "Equity Increase Decrease Percentage xx%";

extern bool   StopTradeAfterEquityIncreased = false;
extern bool   StopTradeAfterEquityDecreased = false;
bool          StopTradeFlag = false;

extern bool   LimitEMA60 = false;       // do we want longs above ema only, shorts below ema only
extern bool   UseMACD = false;          // if true, will use macd >0 for longs only, macd >0 for shorts only
                                       // on crossover, will cancel all pending orders. This will override any
                                       // wantLongs and wantShort settings - at least for now.
                                     
extern bool   UseMAGroup=false;         // if all fast ma > slow ma,do not make short;
                                       // if all fast ma < slow ma, do not make long;  
extern bool   UseStochastic=false;

extern bool   UseSAR = false;
extern double SAR_Step = 0.02;
extern double SAR_Maximum = 0.2;
                                                                                               
extern bool   CloseOpenPositions = false;// if UseMACD or UseMAGroup, do we also close open positions with a loss?

extern bool   ClosePendingPositions = false; // Close Pending Positions Far Away From Present Price

double LastUpdate = 0;          // counter used to note time of last update


//int LisenceStartTime = D'31.12.2009 11:30';
//int LisenceEndTime = D'31.12.2011 11:30';

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
#property show_inputs                  // shows the parameters - thanks Slawa...  

   Equity_Old = AccountEquity();
 
   if (MarketInfo("EURUSD",MODE_DIGITS)==5)
      {
         GridSize *= 10;
         BaseTakeProfit *= 10;
         Slippage *= 10;
         StopLoss *= 10;
         TrailStop *= 10;
      }

//double spread = MarketInfo(Symbol(),MODE_SPREAD);
//if ( BaseTakeProfit <= 0 )                 //
//   { BaseTakeProfit = GridSize-spread; }
//   Print("BaseTakeProfit......................",BaseTakeProfit);

//----
//   GridName = StringConcatenate( "AIGrid", Symbol() );
   return(0);
  }
//+------------------------------------------------------------------------+
//| tests if there is an open position or order in the region of atRate    |
//|     will check for longs if checkLongs is true, else will check        |
//|     for shorts                                                         |
//+------------------------------------------------------------------------+

int IsPosition(double atRate, double inRange, bool checkLongs )
  {
     int CheckPositionRank = 0;                       // check how many rank profit is made in the specified rate and return to the function
     int totalorders = OrdersTotal();
     int type;
     double CurrentOrderTakeProfit;
     double point = MarketInfo(Symbol(),MODE_POINT);
       
     for(int j=0;j<totalorders;j++)                                // scan all orders and positions...
      {
        OrderSelect(j, SELECT_BY_POS);

        if ( ( OrderSymbol()==Symbol() ) && ( OrderMagicNumber() == MagicNumberGrid ) )  // only look if mygrid and symbol...
         {
             ///////////////////////////////////////////////////////////////////////////////////////////////////////
            // don't reset order near the present price
            if( wantBreakout != wantCounter)                // if only long order up, short order down, or only short order up, long order down
              {
                  if ( ( checkLongs && (MathAbs(Ask-atRate) < (inRange*0.9999)) ) || ( !checkLongs && (MathAbs(Bid-atRate) < (inRange*0.9999)) ) )
                  {
                     CheckPositionRank |= 7;
                     return(CheckPositionRank);          // if price near present price, direct return true
                  }
              }    
           
            if(MathAbs( OrderOpenPrice() - atRate ) < (inRange*0.9999 - point*Slippage))// dont look for exact price but price proximity (less than gridsize)
              {
                 type = OrderType();
                 if ( ( checkLongs && ( type == OP_BUY || type == OP_BUYLIMIT  || type == OP_BUYSTOP ) )  || (!checkLongs && ( type == OP_SELL || type == OP_SELLLIMIT  || type == OP_SELLSTOP ) ) )
                 {
                   
                    CurrentOrderTakeProfit = NormalizeDouble( ( OrderTakeProfit() - OrderOpenPrice() ),Digits );
                    CurrentOrderTakeProfit = MathAbs( CurrentOrderTakeProfit );
                   
                    if( ProfitRank1 && ( MathAbs( CurrentOrderTakeProfit - point*BaseTakeProfit ) < point* Slippage ) )
                     {
                        CheckPositionRank |= 1;
                        //Print("CheckPositionRank",CheckPositionRank);
                       
                     }
                    else if( ProfitRank2 && ( MathAbs( CurrentOrderTakeProfit - point*(GridSize+BaseTakeProfit) ) < point* Slippage ) )
                     {                    
                        CheckPositionRank |= 2;
                        //Print("CheckPositionRank",CheckPositionRank);
                     }
                    else if( ProfitRank3 && ( MathAbs( CurrentOrderTakeProfit - point*(GridSize*2+BaseTakeProfit) ) < point* Slippage ) )
                     {
                        CheckPositionRank |= 4;
                        //Print("CheckPositionRank",CheckPositionRank);
                     }
                 }
              } // if MathAbs end here  
         } // if loop end here
      } // for loop end here
   // Print("CheckPositionRank::::::::::::::::::::::",CheckPositionRank);
   return(CheckPositionRank);
  }
 
 

//+------------------------------------------------------------------------+
//| close all open orders              
//+------------------------------------------------------------------------+

void CloseAllOpenOrders()
{
  int total = OrdersTotal();
  for(int i=total-1;i>=0;i--)
  {
    OrderSelect(i, SELECT_BY_POS);
    int type    = OrderType();
    bool result = false;

    if ( ( OrderSymbol()==Symbol() ) && ( OrderMagicNumber() == MagicNumberGrid ) )  // only look if mygrid and symbol...
     {
        //Print("Closing 2 ",type);
        switch(type)
         {
           //Close opened long positions
           case OP_BUY       : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), Slippage, Red );
                               break;
           //Close opened short positions
           case OP_SELL      : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), Slippage, Red );
                               break;
           //Close pending orders
           case OP_BUYLIMIT  : result = true ;
           case OP_BUYSTOP   : result = true ;
           case OP_SELLLIMIT : result = true ;
           case OP_SELLSTOP  : result = true ;
         }
      }
    if(result == false)
    {
      //Alert("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() );
      //Sleep(3000);
    }
  }
  return;
}


//+------------------------------------------------------------------------+
//| cancel all pending orders                                      |
//+------------------------------------------------------------------------+

void CloseAllPendingOrders()
  {
     int totalorders = OrdersTotal();
     for(int j=totalorders-1;j>=0;j--)                                // scan all orders and positions...
      {
        OrderSelect(j, SELECT_BY_POS);

        if ( ( OrderSymbol()==Symbol() ) && ( OrderMagicNumber() == MagicNumberGrid ) )  // only look if mygrid and symbol...
         {
          int type = OrderType();
          bool result = false;
          switch(type)
          {
            case OP_BUYLIMIT  : result = OrderDelete( OrderTicket() ); break;
            case OP_BUYSTOP   : result = OrderDelete( OrderTicket() ); break;
            case OP_SELLLIMIT : result = OrderDelete( OrderTicket() ); break;
            case OP_SELLSTOP  : result = OrderDelete( OrderTicket() ); break;

            case OP_BUY       : result = true ;
            case OP_SELL      : result = true ;
            //Close pending orders
          }
         
         }
      }
      return;
  }

//+------------------------------------------------------------------------+
//| cancel pending long orders                                           |
//+------------------------------------------------------------------------+

void ClosePendingLongOrders( )
  {
     int totalorders = OrdersTotal();
     for(int j=totalorders-1;j>=0;j--)                                // scan all orders and positions...
      {
        OrderSelect(j, SELECT_BY_POS);

        if ( ( OrderSymbol()==Symbol() ) && ( OrderMagicNumber() == MagicNumberGrid ) )  // only look if mygrid and symbol...
         {
          int type = OrderType();
          bool result = false;
          switch(type)
          {
            case OP_BUYLIMIT  : result = OrderDelete( OrderTicket() ); break;
            case OP_BUYSTOP   : result = OrderDelete( OrderTicket() ); break;
            case OP_BUY       : result = true;
            case OP_SELL      : result = true;
            //Close pending orders

            case OP_SELLLIMIT : result = true;
            case OP_SELLSTOP  : result = true;
          }
         }
      }
   return;
  }


//+------------------------------------------------------------------------+
//| cancel pending short orders                                           |
//+------------------------------------------------------------------------+

void ClosePendingShortOrders( )
  {
     int totalorders = OrdersTotal();
     for(int j=totalorders-1;j>=0;j--)                                // scan all orders and positions...
      {
        OrderSelect(j, SELECT_BY_POS);

        if ( ( OrderSymbol()==Symbol() ) && ( OrderMagicNumber() == MagicNumberGrid ) )  // only look if mygrid and symbol...
         {
          int type = OrderType();
          bool result = false;
          switch(type)
          {
            case OP_SELLLIMIT : result = OrderDelete( OrderTicket() ); break;
            case OP_SELLSTOP  : result = OrderDelete( OrderTicket() ); break;
            case OP_BUY       : result = true;
            case OP_SELL      : result = true;
            //Close pending orders
            case OP_BUYLIMIT  : result = true;
            case OP_BUYSTOP   : result = true;

          }
         }
      }
   return;
  }

//+------------------------------------------------------------------------+
//| cancel all pending orders    and close open positions               |
//+------------------------------------------------------------------------+

void CloseAllOrders()
{
  int total = OrdersTotal();
  for(int i=total-1;i>=0;i--)
{
    OrderSelect(i, SELECT_BY_POS);
    int type    = OrderType();
    bool result = false;

    if ( ( OrderSymbol()==Symbol() ) && ( OrderMagicNumber() == MagicNumberGrid ) )  // only look if mygrid and symbol...
     {
//    Print("Closing 2 ",type);
        switch(type)
         {
           //Close opened long positions
           case OP_BUY       : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), Slippage, Red );
                               break;
           //Close opened short positions
           case OP_SELL      : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), Slippage, Red );
                               break;
           //Close pending orders
           case OP_BUYLIMIT  : result = OrderDelete( OrderTicket() ); break;
           case OP_BUYSTOP   : result = OrderDelete( OrderTicket() ); break;
           case OP_SELLLIMIT : result = OrderDelete( OrderTicket() ); break;
           case OP_SELLSTOP  : result = OrderDelete( OrderTicket() ); break;
         }
      }
    if(result == false)
    {
//     Alert("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() );
//     Sleep(3000);
    }
  }
  return;
}

//+------------------------------------------------------------------------+
//| cancel pending long orders    and close open long positions               |
//+------------------------------------------------------------------------+

void CloseLongOrders()
{
  int total = OrdersTotal();
  for(int i=total-1;i>=0;i--)
{
    OrderSelect(i, SELECT_BY_POS);
    int type    = OrderType();
    bool result = false;

    if ( ( OrderSymbol()==Symbol() ) && ( OrderMagicNumber() == MagicNumberGrid ) )  // only look if mygrid and symbol...
     {
//    Print("Closing 2 ",type);
        switch(type)
         {
           //Close opened long positions
           case OP_BUY       : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), Slippage, Red ); break;
           case OP_BUYLIMIT  : result = OrderDelete( OrderTicket() ); break;
           case OP_BUYSTOP   : result = OrderDelete( OrderTicket() ); break;
//Reserve opened short positions
           case OP_SELL      : result = true;
           case OP_SELLLIMIT : result = true;
           case OP_SELLSTOP  : result = true;
         }
      }
    if(result == false)
    {
//     Alert("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() );
//     Sleep(3000);
    }
  }
  return;
}


//+------------------------------------------------------------------------+
//| cancel pending short orders    and close open short positions               |
//+------------------------------------------------------------------------+

void CloseShortOrders()
{
  int total = OrdersTotal();
  for(int i=total-1;i>=0;i--)
{
    OrderSelect(i, SELECT_BY_POS);
    int type    = OrderType();
    bool result = false;

    if ( ( OrderSymbol()==Symbol() ) && ( OrderMagicNumber() == MagicNumberGrid ) )  // only look if mygrid and symbol...
     {
//    Print("Closing 2 ",type);
        switch(type)
         {
//Close opened short positions
            case OP_SELL      : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), Slippage, Red ); break;
            case OP_SELLLIMIT : result = OrderDelete( OrderTicket() ); break;
            case OP_SELLSTOP  : result = OrderDelete( OrderTicket() ); break;

//Reserve opened long positions
            case OP_BUY       : result = true;
            case OP_BUYLIMIT  : result = true;
            case OP_BUYSTOP   : result = true;
        }
      }
    if(result == false)
    {
//     Alert("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() );
//     Sleep(3000);
    }
  }
  return;
}



//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----

   int    i, k, type, ticket, entermode;
   int    totalorders,LongOpenOrders,ShortOpenOrders;
   bool   doit;
   double point, startrate, traderate,spread,traderate_Long;
   double LongLots,ShortLots;
   double Equity_New;
 
//  if (TimeCurrent() >= LisenceEndTime )
//   {
//     Print("Time Expired, please contact robbie.ruan@gmail.com");
//      return(0);
//   }
 
// Parameters defined here are initialized every time, while diefined as extern type initialize just once.

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//if Equity increased EquityIncreasePercentage%, close all

   if(CloseAllWithEquityIncrease)
   {  
      Equity_New = AccountEquity();  
      if( (Equity_New - Equity_Old)/Equity_Old >= EquityIncreasePercentage/100 )
      {
         Print("Close All With Equity Increased: ", EquityIncreasePercentage, "%");
         Equity_Old = Equity_New;
         CloseAllOpenOrders();
         CloseAllPendingOrders();
         if(StopTradeAfterEquityIncreased == true)
         {
            StopTradeFlag = true;
            Print("Stop Trade With Equity Increased, to restart trade, exit and run the EA again");
         }
       
      }
   }
     
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//if Equity Decreased EquityIncreasePercentage%, close all

   if(CloseAllWithEquityDecrease)
   {  
      Equity_New = AccountEquity();  
      if( (Equity_Old - Equity_New)/Equity_Old >= EquityDecreasePercentage/100 )
      {
         Print("Close All With Equity Decreased: ", EquityDecreasePercentage, "%");
         Equity_Old = Equity_New;
         CloseAllOpenOrders();
         CloseAllPendingOrders();
         if(StopTradeAfterEquityDecreased == true)
         {
            StopTradeFlag = true;
            Print("Stop Trade With Equity Decreased, to restart trade, exit and run the EA again");
         }
       
      }
   }
     
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




//   if(StopTradeAfterEquityIncreased == true)
//   {
//      if (StopTradeFlag == true)
//      {
//         Print("EquityIncreased, Stop Trade, to restart trade, exit and reset the EA");
//         return(0);
//      }
//   }



string ScreenString = "DateOfTrade";
ObjectDelete(ScreenString);
ObjectCreate(ScreenString, OBJ_LABEL, 0, 0, 0);
ObjectSetText(ScreenString, ""+TimeToStr(CurTime( ))+" Day"+DayOfWeek(), 12, "Arial Bold", Lime);
ObjectSet(ScreenString, OBJPROP_CORNER, 3);
ObjectSet(ScreenString, OBJPROP_XDISTANCE, 5);
ObjectSet(ScreenString, OBJPROP_YDISTANCE, 5);


//----
  if ( (MathAbs(CurTime()-LastUpdate)> UpdateInterval*60) && (StopTradeFlag == false) )           // we update the first time it is called and every UpdateInterval minutes
   {
   LastUpdate = CurTime();
 
   point = MarketInfo(Symbol(),MODE_POINT);
 
   if(ConsiderSpread == true)
   {
      spread = MarketInfo(Symbol(),MODE_SPREAD);
      spread = point*spread;
   }
   else
   {
      spread = 0;
   }
   LongLots = Lots;
   ShortLots = Lots;
 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Equity Control Lots
 
   if(EquityControlLots)
   {
      //Print("Account equity ================== ",AccountEquity());
      double EquityPercentage = AccountEquity()/AccountBalance();
      //Print("===========================EquityPercentage=====",EquityPercentage);
      int EquityTimes = MathFloor( (AccountEquity()/BaseEquity) * EquityPercentage );  // how many time is present equity times BaseEquity
      //Print("EquityTimes===========",EquityTimes);    
      if(EquityTimes >= 1)
      {
         Lots = BaseLots*EquityTimes;                 // total new open Lots
         LongLots = Lots;
         ShortLots = Lots;
       
      }
      //Print("NewLots====================================", Lots);
   }
 
///////////////////////////////////////////////////////////////////////////////////////////////////
//calulate total open order quantiies

   totalorders = OrdersTotal();
   LongOpenOrders = 0;
   ShortOpenOrders = 0;
   for(i=0;i<totalorders;i++)
   {
      OrderSelect(i,SELECT_BY_POS);
      type = OrderType();
      if(type == OP_BUY)
         LongOpenOrders++;
      else if(type == OP_SELL)
         ShortOpenOrders++;
   }
////////////////////////////////////////////////////////////////////////////////////////////
//Unbalanced OpenOrders ControlLots, the smaller long short ratio, the more long lots and less short lots, vice visa
   if(unEquLongShortControlLots)
   {
     
      if( (LongOpenOrders >=10 || ShortOpenOrders >= 10) && Lots > 0.1)
      {
         LongLots = Lots * (2.0*ShortOpenOrders/(LongOpenOrders+ShortOpenOrders));
         LongLots = NormalizeDouble(LongLots,2);
                   
         ShortLots = Lots*2-LongLots;
           
         if(LongLots == 0)
            {
               LongLots += BaseLots;
               ShortLots -= BaseLots;
            }
           
         else if(ShortLots == 0)
            {
               ShortLots += BaseLots;
               LongLots -= BaseLots;
            }
      }
     
      //Print("LongOpenOrders::::::::::::::",LongOpenOrders);
      //Print(":::::::ShortOpenOrders::::::::::::::",ShortOpenOrders);
   }
 

   //Print("LongLots============================================", LongLots);
   //Print("=========ShortLots========================================", ShortLots);



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Trailing stop
   if (TrailStop > 0) TrailingStop(TrailStop);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


// default base value is low price, if Low value is 0, then check if High value also 0, if both 0, then use market price as base value.
 
   if( Grid_Low > 0 )
      startrate=Grid_Low;                      
   else if( (Grid_Low == 0) && Grid_High>0 )
      startrate=Grid_High;
   else
   {
      startrate = ( Bid + point*GridSize/2 ) / point / GridSize;    // round to a number of ticks divisible by GridSize
      k = startrate ;
      k = k * GridSize ;
      startrate = k * point - GridSize*GridSteps/2*point ;          // calculate the lowest entry point
   }
 
//   Print("startrate::::::::::",startrate);
   double EMA60=iMA(NULL,PERIOD_H1,60,0,MODE_EMA,PRICE_CLOSE,0);
 
/////////////////////////////////////////////////////////////////////////////////////////////////////
// if use MACD

   if ( UseMACD )  {
      double Macd0=iMACD(NULL,PERIOD_H4,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
      double Macd1=iMACD(NULL,PERIOD_H4,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
      double Macd2=iMACD(NULL,PERIOD_H4,12,26,9,PRICE_CLOSE,MODE_MAIN,2);
       if( Macd0>0 && Macd1>0  &&  Macd2<0)     // cross up
        {
         CloseAllPendingOrders();
         if ( CloseOpenPositions == true ) { CloseAllOrders(); }
        }
       if( Macd0<0 && Macd1<0  &&  Macd2>0)     // cross down
        {
         CloseAllPendingOrders();
         if ( CloseOpenPositions == true ) { CloseAllOrders(); }
        }
       wantLongs = false;
       wantShorts = false;
       if( Macd0>0 && Macd1>0  &&  Macd2>0)     // is well above zero
        {
         wantLongs = true;
        }
       if( Macd0<0 && Macd1<0  &&  Macd2<0)     // is well below zero
        {
         wantShorts = true;
        }
   }

 //////////////////////////////////////////////////////////////////////////////////////////////////////////
 // if Use SAR
 
   if ( UseSAR )
   {
      wantLongs = false;
      wantShorts = false;
      double CLOSE0 = iClose(NULL, PERIOD_W1, 0);
      double SAR0 = iSAR(NULL, PERIOD_W1, SAR_Step, SAR_Maximum, 0);
     
      if(SAR0 < CLOSE0)
      {
         wantLongs = true;
      }
     
      if(SAR0 > CLOSE0)
      {
         wantShorts = true;
      }
     
   }
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// when use MA Group, ADX must be used

   if(UseMAGroup)
   {
      double SMA5=iMA(NULL,PERIOD_M15,5,0,MODE_SMA,PRICE_CLOSE,0);
      double SMA13=iMA(NULL,PERIOD_M15,13,0,MODE_SMA,PRICE_CLOSE,0);
      double SMA21=iMA(NULL,PERIOD_M15,21,0,MODE_SMA,PRICE_CLOSE,0);
      double SMA60=iMA(NULL,PERIOD_M15,60,0,MODE_SMA,PRICE_CLOSE,0);
      double SMA200=iMA(NULL,PERIOD_M15,200,0,MODE_SMA,PRICE_CLOSE,0);
 
// MA Group Divergent Trend Up  
      if(SMA5>SMA13 && SMA13>SMA21 && SMA21>SMA60 && SMA60>SMA200 && (SMA5-SMA21>0.0040))
      {
         //KD Cross Up
         if( (!UseStochastic || ((iStochastic(NULL,PERIOD_H1,5,3,3,MODE_SMA,0,MODE_MAIN,0)-iStochastic(NULL,PERIOD_H1,5,3,3,MODE_SMA,0,MODE_SIGNAL,0))) > 2) )
         {
            //Print("Cross Up MAIN:::::::::::::::::::::::::::",iStochastic(NULL,PERIOD_H1,5,3,3,MODE_SMA,0,MODE_MAIN,0));
            //Print("Signal::::",iStochastic(NULL,PERIOD_H1,5,3,3,MODE_SMA,0,MODE_SIGNAL,0));
            //Sleep(5000);
            ClosePendingShortOrders();
            if(CloseOpenPositions==true)  { CloseShortOrders(); }
            wantLongs=true;
            wantShorts=false;
         }
      }
//MA Group Divergent Trend Down  
      else if(SMA5<SMA13 && SMA13<SMA21 && SMA21<SMA60 && SMA60<SMA200 && (SMA21-SMA5>0.0040))
      {
         //KD Cross Down
         if( (!UseStochastic || ((iStochastic(NULL,PERIOD_H1,5,3,3,MODE_SMA,0,MODE_SIGNAL,0)-iStochastic(NULL,PERIOD_H1,5,3,3,MODE_SMA,0,MODE_MAIN,0))) > 2) )
         {
            //Print("Cross Down MAIN...............................",iStochastic(NULL,PERIOD_H1,5,3,3,MODE_SMA,0,MODE_MAIN,0));
            //Print("Signal::::",iStochastic(NULL,PERIOD_H1,5,3,3,MODE_SMA,0,MODE_SIGNAL,0));
            //Sleep(5000);
            ClosePendingLongOrders();
            if(CloseOpenPositions==true)  { CloseLongOrders(); }
            wantLongs=false;
            wantShorts=true;
         }
      }
      else
      {
         wantLongs=false;
         wantShorts=false;
         PlaySound("alert2.wav");
      }
   }
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

   for( i=0;i<GridSteps;i++)
   {                  
      if( (Grid_Low == 0) && Grid_High > 0 )
         traderate = startrate - i*point*GridSize;
      else
         traderate = startrate + i*point*GridSize;   // Whether Grid_Low >0 or =0, both put net from bottom up
         traderate_Long = traderate+spread;
     
      if((Grid_Low > 0 && traderate < Grid_Low) || (Grid_High > 0 &&  traderate > Grid_High))
         break;
// all pending orders will not exeed order high low limit

     if ( wantLongs && (!LimitEMA60 || traderate > EMA60) && (LongLots > 0) && (((GridMaxOpenEachSide > 0) && (LongOpenOrders < GridMaxOpenEachSide)) || (GridMaxOpenEachSide == 0)) )
       {
         int CheckPositionRank=255;
         CheckPositionRank=IsPosition(traderate_Long,point*GridSize,true);
         // Print("CheckPositionRank>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",CheckPositionRank);
         // Print("CheckPositionRank & 1:::::::::::",CheckPositionRank & 1);
         // Print("CheckPositionRank & 2:::::::::::",CheckPositionRank & 2);
         // Print("CheckPositionRank & 4:::::::::::",CheckPositionRank & 4);
       
         //check profit rank 1
         if ( ProfitRank1 && ((CheckPositionRank & 1) == 0) )           // test if i have no open orders profit rank 1 close to my price: if so, put one on
          {
            double myStopLoss = 0;
           
            if(FixedAllLongStopLoss>0)
               myStopLoss=FixedAllLongStopLoss;
            else if( StopLoss > 0 )
               {
                  myStopLoss = traderate_Long-point*StopLoss;
               }
             
            if( traderate_Long > Ask )
               { entermode = OP_BUYSTOP; }
            else
               { entermode = OP_BUYLIMIT ; }
            if( ((traderate_Long > Ask ) && (wantBreakout)) || ((traderate_Long <= Ask ) && (wantCounter)) )
               {
                  ticket=OrderSend(Symbol(),entermode,LongLots,traderate_Long,0,myStopLoss,traderate_Long+point*BaseTakeProfit,GridName,MagicNumberGrid,0,Green);
               }
          }
       
         //check profit rank 2
         if ( ProfitRank2 && ((CheckPositionRank & 2) == 0) )           // test if i have no open orders profit rank 2 close to my price: if so, put one on
          {
            myStopLoss = 0;
           
            if(FixedAllLongStopLoss>0)
               myStopLoss=FixedAllLongStopLoss;
            else if( StopLoss > 0 )
               {
                  myStopLoss = traderate_Long-point*StopLoss;
               }
             
            if( traderate_Long > Ask )
               { entermode = OP_BUYSTOP; }
            else
               { entermode = OP_BUYLIMIT ; }
            if( ((traderate_Long > Ask ) && (wantBreakout)) || ((traderate_Long <= Ask ) && (wantCounter)) )
               {
                  ticket=OrderSend(Symbol(),entermode,LongLots,traderate_Long,0,myStopLoss,traderate_Long+point*(GridSize+BaseTakeProfit),GridName,MagicNumberGrid,0,Green);
               }
          }
       
     
         //check profit rank 3
         if ( ProfitRank3 && ((CheckPositionRank & 4) == 0) )          // test if i have no open orders profit rank 3 close to my price: if so, put one on
          {
            myStopLoss = 0;
           
            if(FixedAllLongStopLoss>0)
               myStopLoss=FixedAllLongStopLoss;
            else if( StopLoss > 0 )
               {
                  myStopLoss = traderate_Long-point*StopLoss;
               }
             
            if( traderate_Long > Ask )
               { entermode = OP_BUYSTOP; }
            else
               { entermode = OP_BUYLIMIT ; }
            if( ((traderate_Long > Ask ) && (wantBreakout)) || ((traderate_Long <= Ask ) && (wantCounter)) )
               {
                  ticket=OrderSend(Symbol(),entermode,LongLots,traderate_Long,0,myStopLoss,traderate_Long+point*(GridSize*2+BaseTakeProfit),GridName,MagicNumberGrid,0,Green);
               }
          }
       
       }  
     
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

     if( wantShorts && (!LimitEMA60 || traderate < EMA60) && (ShortLots > 0) && (((GridMaxOpenEachSide > 0) && (ShortOpenOrders < GridMaxOpenEachSide)) || (GridMaxOpenEachSide == 0)) )
       {
         CheckPositionRank = 255;
         CheckPositionRank = IsPosition(traderate,point*GridSize,false);
         // Print("CheckPositionRank..................................................................",CheckPositionRank);
         // Print("CheckPositionRank & 1:::::::::::",CheckPositionRank & 1);
         // Print("CheckPositionRank & 2:::::::::::",CheckPositionRank & 2);
         // Print("CheckPositionRank & 4:::::::::::",CheckPositionRank & 4);
       
         //check profit rank 1
         if ( ProfitRank1 && ((CheckPositionRank & 1) == 0) )           // test if i have no open orders profit rank 1 close to my price: if so, put one on
          {
             myStopLoss = 0;
           
             if( FixedAllShortStopLoss > 0 )
               myStopLoss=FixedAllShortStopLoss;
             else if ( StopLoss > 0 )
               {
                  myStopLoss = traderate+point*StopLoss;
               }
           
             if( traderate > Bid )
               { entermode = OP_SELLLIMIT; }
             else
               { entermode = OP_SELLSTOP ; }
             
             if( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) )
               {
                  ticket=OrderSend(Symbol(),entermode,ShortLots,traderate,0,myStopLoss,traderate-point*BaseTakeProfit,GridName,MagicNumberGrid,0,Red);
               }
          }
         
           //check profit rank 2
         if ( ProfitRank2 && ((CheckPositionRank & 2) == 0) )           // test if i have no open orders profit rank 2 close to my price: if so, put one on
          {
             myStopLoss = 0;
           
             if( FixedAllShortStopLoss > 0 )
               myStopLoss=FixedAllShortStopLoss;
             else if ( StopLoss > 0 )
               {
                  myStopLoss = traderate+point*StopLoss;
               }
           
             if( traderate > Bid )
               { entermode = OP_SELLLIMIT; }
             else
               { entermode = OP_SELLSTOP ; }
             
             if( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) )
               {
                  ticket=OrderSend(Symbol(),entermode,ShortLots,traderate,0,myStopLoss,traderate-point*(GridSize+BaseTakeProfit),GridName,MagicNumberGrid,0,Red);
               }
          }
 
         //check profit rank 3
         if ( ProfitRank3 && ((CheckPositionRank & 4) == 0) )           // test if i have no open orders profit rank 3 close to my price: if so, put one on
          {
             myStopLoss = 0;
           
             if( FixedAllShortStopLoss > 0 )
               myStopLoss=FixedAllShortStopLoss;
             else if ( StopLoss > 0 )
               {
                  myStopLoss = traderate+point*StopLoss;
               }
           
             if( traderate > Bid )
               { entermode = OP_SELLLIMIT; }
             else
               { entermode = OP_SELLSTOP ; }
             
             if( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) )
               {
                  ticket=OrderSend(Symbol(),entermode,ShortLots,traderate,0,myStopLoss,traderate-point*(GridSize*2+BaseTakeProfit),GridName,MagicNumberGrid,0,Red);
               }
          }          
       } //short "if" end here
     }// Grid "for" end here
 

   if(ClosePendingPositions)          // close pending orders far away from present price
   {
      for(i=0;i<OrdersTotal();i++)
      {
         OrderSelect(i, SELECT_BY_POS);
         type=OrderType();
         if( ( (type==OP_BUYLIMIT || type==OP_BUYSTOP) && MathAbs(OrderOpenPrice()-Ask) > point*GridSize*(GridSteps*0.5) ) ||  ( (type==OP_SELLLIMIT || type==OP_SELLSTOP) && MathAbs(OrderOpenPrice()-Bid) > point*GridSize*(GridSteps*0.5) ) )// Orders outside the GridSize
         {
            OrderDelete(OrderTicket());
         }
      }
     
   } //close pending order if end here
 
   }// time check "if" end here
   return(0);
  }
//+------------------------------------------------------------------+


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Trailing Stop function

void TrailingStop(int TrailStop)
{
   if (TrailStop >= 5)
   {
      int total = OrdersTotal();
      for (int i = 0; i < total; i++)
      {
         OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
         if ( OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumberGrid )
         {
            if (OrderType() == OP_BUY)
            {
               if ( Bid - OrderOpenPrice() > TrailStop * MarketInfo(OrderSymbol(), MODE_POINT) )
               {
                  if (OrderStopLoss() < Bid - TrailStop * MarketInfo(OrderSymbol(), MODE_POINT) )
                  {
                     OrderModify(OrderTicket(), OrderOpenPrice(), Bid - TrailStop * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(), OrderExpiration(),CLR_NONE);
                  }
               }
             
            }
           
            else if (OrderType() == OP_SELL)
            {
               if (OrderOpenPrice() - Ask > TrailStop * MarketInfo(OrderSymbol(), MODE_POINT))
               {
                  if (OrderStopLoss() > Ask + TrailStop * MarketInfo(OrderSymbol(), MODE_POINT) || OrderStopLoss() == 0.0)
                  {
                     OrderModify(OrderTicket(), OrderOpenPrice(), Ask + TrailStop * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(), OrderExpiration(),CLR_NONE);
                  }
               }    
            } //else end
         }// magic end
      } // for total end
   }// if TrailStop >=5 end
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////






//---- input parameters ---------------------------------------------+

extern int       INCREMENT=35;
extern double    LOTS=0.1;
extern int       LEVELS=3; 
extern double    MAX_LOTS=99;
extern int       MAGIC=1803;
extern bool      CONTINUE=true;
extern bool      MONEY_MANAGEMENT=false;
extern int       RISK_RATIO=2;
//+------------------------------------------------------------------+

bool             UseProfitTarget=false;
bool             UsePartialProfitTarget=false;
int              Target_Increment = 50;
int              First_Target = 20;
bool             UseEntryTime=false;
int              EntryTime=0;

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

bool Enter=true;
int nextTP;

int init()
  {
//+------------------------------------------------------------------+ 
   nextTP = First_Target;
//+------------------------------------------------------------------+
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   int ticket, cpt, profit, total=0, BuyGoalProfit, SellGoalProfit, PipsLot;
   double ProfitTarget=INCREMENT*2, BuyGoal=0, SellGoal=0, spread=(Ask-Bid)/Point, InitialPrice=0;
//----
  
   if(INCREMENT<MarketInfo(Symbol(),MODE_STOPLEVEL)+spread) INCREMENT=1+MarketInfo(Symbol(),MODE_STOPLEVEL)+spread;
   if(MONEY_MANAGEMENT) LOTS=NormalizeDouble(AccountBalance()*AccountLeverage()/1000000*RISK_RATIO,0)*MarketInfo(Symbol(),MODE_MINLOT);
   if(LOTS<MarketInfo(Symbol(),MODE_MINLOT))
   {
      Comment("Not Enough Free Margin to begin");
      return(0);
   }
   for(cpt=1;cpt<LEVELS;cpt++) PipsLot+=cpt*INCREMENT;
   for(cpt=0;cpt<OrdersTotal();cpt++)
   {
      OrderSelect(cpt,SELECT_BY_POS,MODE_TRADES);
      if(OrderMagicNumber()==MAGIC && OrderSymbol()==Symbol())
      {
         total++;
         if(!InitialPrice) InitialPrice=StrToDouble(OrderComment());
         if(UsePartialProfitTarget && UseProfitTarget && OrderType()<2)
         {
            double val=getPipValue(OrderOpenPrice(),OrderType());
            takeProfit(val,OrderTicket()); 
         }
      }
   }
   if(total<1 && Enter && (!UseEntryTime || (UseEntryTime && Hour()==EntryTime)))
   {
      if(AccountFreeMargin()<(100*LOTS))
      {
         Print("Not enough free margin to begin");
         return(0);
      }
      // - Open Check - Start Cycle
      InitialPrice=Ask;
      SellGoal=InitialPrice-(LEVELS+1)*INCREMENT*Point;
      BuyGoal=InitialPrice+(LEVELS+1)*INCREMENT*Point;
      for(cpt=1;cpt<=LEVELS;cpt++)
      {
         OrderSend(Symbol(),OP_BUYSTOP,LOTS,InitialPrice+cpt*INCREMENT*Point,2,SellGoal,BuyGoal,DoubleToStr(InitialPrice,MarketInfo(Symbol(),MODE_DIGITS)),MAGIC,0);
         OrderSend(Symbol(),OP_SELLSTOP,LOTS,InitialPrice-cpt*INCREMENT*Point,2,BuyGoal+spread*Point,SellGoal+spread*Point,DoubleToStr(InitialPrice,MarketInfo(Symbol(),MODE_DIGITS)),MAGIC,0);
      }
    } // initial setup done - all channels are set up
    else // We have open Orders
    {
      BuyGoal=InitialPrice+INCREMENT*(LEVELS+1)*Point;
      SellGoal=InitialPrice-INCREMENT*(LEVELS+1)*Point;
      total=OrdersHistoryTotal();
      for(cpt=0;cpt<total;cpt++)
      {
         OrderSelect(cpt,SELECT_BY_POS,MODE_HISTORY);
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC &&  StrToDouble(OrderComment())==InitialPrice){EndSession();return(0);}
      }
      if(UseProfitTarget && CheckProfits(LOTS,OP_SELL,true,InitialPrice)>ProfitTarget) {EndSession();return(0);}
      BuyGoalProfit=CheckProfits(LOTS,OP_BUY,false,InitialPrice);
      SellGoalProfit=CheckProfits(LOTS,OP_SELL,false,InitialPrice);
      if(BuyGoalProfit<ProfitTarget)
      // - Incriment Lots Buy
      {
         for(cpt=LEVELS;cpt>=1 && BuyGoalProfit<ProfitTarget;cpt--)
         {
            if(Ask<=(InitialPrice+(cpt*INCREMENT-MarketInfo(Symbol(),MODE_STOPLEVEL))*Point))
            {
               ticket=OrderSend(Symbol(),OP_BUYSTOP,cpt*LOTS,InitialPrice+cpt*INCREMENT*Point,2,SellGoal,BuyGoal,DoubleToStr(InitialPrice,MarketInfo(Symbol(),MODE_DIGITS)),MAGIC,0);
            }
            if(ticket>0) BuyGoalProfit+=LOTS*(BuyGoal-InitialPrice-cpt*INCREMENT*Point)/Point;
         }
      }
      if(SellGoalProfit<ProfitTarget)
      // - Increment Lots Sell
      {
         for(cpt=LEVELS;cpt>=1 && SellGoalProfit<ProfitTarget;cpt--)
         {
            if(Bid>=(InitialPrice-(cpt*INCREMENT-MarketInfo(Symbol(),MODE_STOPLEVEL))*Point))
            {
               ticket=OrderSend(Symbol(),OP_SELLSTOP,cpt*LOTS,InitialPrice-cpt*INCREMENT*Point,2,BuyGoal+spread*Point,SellGoal+spread*Point,DoubleToStr(InitialPrice,MarketInfo(Symbol(),MODE_DIGITS)),MAGIC,0);
            }
            if(ticket>0) SellGoalProfit+=LOTS*(InitialPrice-cpt*INCREMENT*Point-SellGoal-spread*Point)/Point;
         }
      }
   }
//+------------------------------------------------------------------+   

    Comment("mGRID EXPERT ADVISOR ver 2.0\n",
            "FX Acc Server:",AccountServer(),"\n",
            "Date: ",Month(),"-",Day(),"-",Year()," Server Time: ",Hour(),":",Minute(),":",Seconds(),"\n",
            "Minimum Lot Sizing: ",MarketInfo(Symbol(),MODE_MINLOT),"\n",
            "Account Balance:  $",AccountBalance(),"\n",
            "Symbol: ", Symbol(),"\n",
            "Price:  ",NormalizeDouble(Bid,4),"\n",
            "Pip Spread:  ",MarketInfo("EURUSD",MODE_SPREAD),"\n",
            "Increment=" + INCREMENT,"\n",
            "Lots:  ",LOTS,"\n",
            "Levels: " + LEVELS,"\n");
   return(0);
}

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

int CheckProfits(double LOTS, int Goal, bool Current, double InitialPrice)
{
   int profit=0, cpt;
   if(Current)//return current profit
   {
      for(cpt=0;cpt<OrdersTotal();cpt++)
      {
         OrderSelect(cpt, SELECT_BY_POS, MODE_TRADES);
         if(OrderSymbol()==Symbol() && StrToDouble(OrderComment())==InitialPrice)
         {
            if(OrderType()==OP_BUY) profit+=(Bid-OrderOpenPrice())/Point*OrderLots()/LOTS;
            if(OrderType()==OP_SELL) profit+=(OrderOpenPrice()-Ask)/Point*OrderLots()/LOTS;
         }
      }
      return(profit);
   }
   else
   {
      if(Goal==OP_BUY)
      {
         for(cpt=0;cpt<OrdersTotal();cpt++)
         {
            OrderSelect(cpt, SELECT_BY_POS, MODE_TRADES);
            if(OrderSymbol()==Symbol() && StrToDouble(OrderComment())==InitialPrice)
            {
               if(OrderType()==OP_BUY) profit+=(OrderTakeProfit()-OrderOpenPrice())/Point*OrderLots()/LOTS;
               if(OrderType()==OP_SELL) profit-=(OrderStopLoss()-OrderOpenPrice())/Point*OrderLots()/LOTS;
               if(OrderType()==OP_BUYSTOP) profit+=(OrderTakeProfit()-OrderOpenPrice())/Point*OrderLots()/LOTS;
            }
         }
         return(profit);
      }
      else
      {
         for(cpt=0;cpt<OrdersTotal();cpt++)
         {
            OrderSelect(cpt, SELECT_BY_POS, MODE_TRADES);
            if(OrderSymbol()==Symbol() && StrToDouble(OrderComment())==InitialPrice)
            {
               if(OrderType()==OP_BUY) profit-=(OrderOpenPrice()-OrderStopLoss())/Point*OrderLots()/LOTS;
               if(OrderType()==OP_SELL) profit+=(OrderOpenPrice()-OrderTakeProfit())/Point*OrderLots()/LOTS;
               if(OrderType()==OP_SELLSTOP) profit+=(OrderOpenPrice()-OrderTakeProfit())/Point*OrderLots()/LOTS;              
            }
         }
         return(profit);
      }
   }
}

bool EndSession()
{
   int cpt, total=OrdersTotal();
   for(cpt=0;cpt<total;cpt++)
   {
      Sleep(3000);
      OrderSelect(cpt,SELECT_BY_POS,MODE_TRADES);
      if(OrderSymbol()==Symbol() && OrderType()>1) OrderDelete(OrderTicket());
      else if(OrderSymbol()==Symbol() && OrderType()==OP_BUY) OrderClose(OrderTicket(),OrderLots(),Bid,3);
      else if(OrderSymbol()==Symbol() && OrderType()==OP_SELL) OrderClose(OrderTicket(),OrderLots(),Ask,3);
      
      }
      if(!CONTINUE)  Enter=false;
      return(true);
}


double getPipValue(double ord,int dir)
{
   double val;
   RefreshRates();
   if(dir == 1) val=(NormalizeDouble(ord,Digits) - NormalizeDouble(Ask,Digits));
   else val=(NormalizeDouble(Bid,Digits) - NormalizeDouble(ord,Digits));
   val = val/Point;
   return(val);   
}

//========== FUNCTION takeProfit

void takeProfit(int current_pips, int ticket)
{
   if(OrderSelect(ticket, SELECT_BY_TICKET))
   {

      if(current_pips >= nextTP && current_pips < (nextTP + Target_Increment))
      {
         if(OrderType()==1)
         {
            if(OrderClose(ticket, MAX_LOTS, Ask, 3))
            nextTP+=Target_Increment;
            else
            Print("Error closing order : ",GetLastError()); 
         } 
         else
         {
            if(OrderClose(ticket, MAX_LOTS, Bid, 3))
            nextTP+=Target_Increment;
            else
            Print("Error closing order : ",GetLastError()); 
         }        
      }
   }
}















//+------------------------------------------------------------------+
//|                                   Copyright ฉ 2010, Bernd Kreuss |
//|                        PayPal donations go here -> 7bit@arcor.de |
//+------------------------------------------------------------------+
#property copyright "ฉ Bernd Kreuss, Version 2010.6.11.1"
#property link      "http://sites.google.com/site/prof7bit/"

#include <common_functions.mqh>
#include <offline_charts.mqh> 
//#include <oanda.mqh> 

extern double lots = 0.01; // lots to use per trade
//extern double oanda_factor = 25000;
extern int stop_distance = 20;
extern int auto_tp = 2; // auto-takeprofit this many levels (roughly) above the BE point
extern bool is_ecn_broker = false; // different market order procedure when resuming after pause

extern color clr_breakeven_level = Lime;
extern color clr_buy = Blue;
extern color clr_sell = Red;
extern color clr_gridline = Lime;
extern color clr_stopline_active = Magenta;
extern color clr_stopline_triggered = Aqua;
extern string sound_grid_trail = "";
extern string sound_grid_step = "";
extern string sound_order_triggered = "";
extern string sound_stop_all = "";

string name = "snow";

double pip;
double points_per_pip;
string comment;
int magic;
bool running;
int direction;
double last_line;
int level; // current level, signed, minus=short, calculated in trade()
double realized; // total realized (all time) (calculated in info())
double cycle_total_profit; // total profit since cycle started (calculated in info())
double stop_value; // dollars (account) per single level (calculated in info())
double auto_tp_price; // the price where auto_tp should trigger, calculated during break even calc.
double auto_tp_profit; // rough estimation of auto_tp profit, calculated during break even calc.

#define SP "                                    "

// trading direction
#define BIDIR 0
#define LONG  1
#define SHORT 2


void defaults(){
   /*
   IS_ECN_BROKER = true;
   //auto_tp = 2;
   
   if (IsTesting()){
      return(0);
   }
   if (Symbol6() == "GBPUSD"){
      lots = 0.1;
      oanda_factor = 900;
      stop_distance = 30;
   }
   if (Symbol6() == "EURUSD"){
      lots = 0.1;
      oanda_factor = 1800;
      stop_distance = 30;
   }
   if (Symbol6() == "USDCHF"){
      lots = 0.1;
      oanda_factor = 1800;
      stop_distance = 20;
   }
   if (Symbol6() == "USDJPY"){
      lots = 0.1;
      oanda_factor = 1800;
      stop_distance = 30;
   }
   
   sound_grid_step = "expert.wav";
   sound_grid_trail = "alert2.wav";
   sound_stop_all = "alert.wav";
   sound_order_triggered = "alert.wav";
   */
}


int init(){
   if (!IsDllsAllowed()){
      MessageBox("DLL imports must be allowed!", "Snowball");
      return(-1);
   }
      
   IS_ECN_BROKER = is_ecn_broker;
   CLR_BUY_ARROW = clr_buy;
   CLR_SELL_ARROW = clr_sell;
   CLR_CROSSLINE_ACTIVE = clr_stopline_active;
   CLR_CROSSLINE_TRIGGERED = clr_stopline_triggered;
   
   defaults();

   points_per_pip = pointsPerPip();
   pip = Point * points_per_pip;
   
   comment = name + "_" + Symbol6();
   magic = makeMagicNumber(name + "_" + Symbol());
   
   if (last_line == 0){
      last_line = getLine();
   }
   
   if (IsTesting()){
      setGlobal("realized", 0);
      setGlobal("running", 0);
   }
   
   readVariables();
   
   if (IsTesting() && !IsVisualMode()){
      Print("!!! This is not an automated strategy! Automated backtesting is nonsense! Starting in bidirectional mode!");
      running = true;
      direction = BIDIR;
      placeLine(Bid);
   }
      
   info();
}

int deinit(){
   deleteStartButtons();
   deleteStopButtons();
   storeVariables();
   if (UninitializeReason() == REASON_PARAMETERS){
      Comment("Parameters changed, pending orders deleted, will be replaced with the next tick");
      closeOpenOrders(OP_SELLSTOP, magic);
      closeOpenOrders(OP_BUYSTOP, magic);
   }else{
      Comment("EA removed, open orders, trades and status untouched!");
   }
}

void onTick(){
   recordEquity(name+Symbol6(), PERIOD_H1, magic);
   //checkOanda(magic, oanda_factor);
   checkLines();
   checkButtons();
   trade();
   info();
   checkAutoTP();
   if(!IsTesting()){
      plotNewOpenTrades(magic);
      plotNewClosedTrades(magic);
   }
}

void onOpen(){
}

void storeVariables(){
   setGlobal("running", running);
   setGlobal("direction", direction);
}

void readVariables(){
   running = getGlobal("running");
   direction = getGlobal("direction");
}

void deleteStartButtons(){
   ObjectDelete("start_long");
   ObjectDelete("start_short");
   ObjectDelete("start_bidir");
}

void deleteStopButtons(){
   ObjectDelete("stop");
   ObjectDelete("pause");
}

/**
* mark the start (or resume) of the cycle in the chart 
*/
void startArrow(){
   string aname = "cycle_start_" + TimeToStr(TimeCurrent());
   ObjectCreate(aname, OBJ_ARROW, 0, TimeCurrent(), Close[0]);
   ObjectSet(aname, OBJPROP_ARROWCODE, 5);
   ObjectSet(aname, OBJPROP_COLOR, clr_gridline);
   ObjectSet(aname, OBJPROP_BACK, true);
}

/**
* mark the end (or pause) of the cycle in the chart 
*/
void endArrow(){
   string aname = "cycle_end_" + TimeToStr(Time[0]);
   ObjectCreate(aname, OBJ_ARROW, 0, TimeCurrent(), Close[0]);
   ObjectSet(aname, OBJPROP_ARROWCODE, 6);
   ObjectSet(aname, OBJPROP_COLOR, clr_gridline);
   ObjectSet(aname, OBJPROP_BACK, true);
}

void stop(){
   endArrow();
   deleteStopButtons();
   closeOpenOrders(-1, magic);
   running = false;
   storeVariables();
   setGlobal("realized", getProfitRealized(magic)); // store this only on pyramid close
   //checkOanda(magic, oanda_factor);
   if (sound_stop_all != ""){
      PlaySound(sound_stop_all);
   }
}

void go(int mode){
   startArrow();
   deleteStartButtons();
   running = true;
   direction = mode;
   storeVariables();
   resume();
}

void pause(){
   endArrow();
   deleteStopButtons();
   label("paused_level", 15, 100, 1, level, Yellow);
   closeOpenOrders(-1, magic);
   running = false;
   storeVariables();
   //checkOanda(magic, oanda_factor);
   if (sound_stop_all != ""){
      PlaySound(sound_stop_all);
   }
}

/**
* resume trading after we paused it.
* Find the text label containing the level where we hit pause
* and re-open the corresponding amounts of lots, then delete the label.
*/ 
void resume(){
   int i;
   double sl;
   double line = getLine();
   level = StrToInteger(ObjectDescription("paused_level"));
   
   if (direction == LONG){
      level = MathAbs(level);
   }
   
   if (direction == SHORT){
      level = -MathAbs(level);
   }
   
   if (level > 0){
      for (i=1; i<=level; i++){
         sl = line - pip * i * stop_distance;
         buy(lots, sl, 0, magic, comment);
      }
   }
   
   if (level < 0){
      for (i=1; i<=-level; i++){
         sl = line + pip * i * stop_distance;
         sell(lots, sl, 0, magic, comment);
      }
   }
      
   ObjectDelete("paused_level");
}

void checkLines(){
   if (crossedLine("stop")){
      stop();
   }
   if (crossedLine("pause")){
      pause();
   }
   if (crossedLine("start long")){
      go(LONG);
   }
   if (crossedLine("start short")){
      go(SHORT);
   }
   if (crossedLine("start bidir")){
      go(BIDIR);
   }   
}

void checkButtons(){
   if(!running){
      deleteStopButtons();
      if (labelButton("start_long", 15, 15, 1, "start long", Lime)){
         go(LONG);
      }
      if (labelButton("start_short", 15, 30, 1, "start short", Lime)){
         go(SHORT);
      }
      if (labelButton("start_bidir", 15, 45, 1, "start bidirectional", Lime)){
         go(BIDIR);
      }
   }
   
   if (running){
      deleteStartButtons();
      if (labelButton("stop", 15, 15, 1, "stop", Red)){
         stop();
      }
      if (labelButton("pause", 15, 30, 1, "pause", Yellow)){
         pause();
      }
   }
}

void checkAutoTP(){
   if (auto_tp > 0 && auto_tp_price > 0){
      if (level > 0 && Close[0] >= auto_tp_price){
         stop();
      }
      if (level < 0 && Close[0] <= auto_tp_price){
         stop();
      }
   }
}

void placeLine(double price){
   horizLine("last_order", price, clr_gridline, SP + "grid position");
   last_line = price;
   WindowRedraw();
}

double getLine(){
   return(ObjectGet("last_order", OBJPROP_PRICE1));
}

bool lineMoved(){
   double line = getLine();
   if (line != last_line){
      // line has been moved by external forces (hello wb ;-)
      if (MathAbs(line - last_line) < stop_distance * pip){
         // minor adjustment by user
         last_line = line;
         return(true);
      }else{
         // something strange (gap? crash? line deleted?)
         if (MathAbs(Bid - last_line) < stop_distance * pip){
            // last_line variable still near price and thus is valid.
            placeLine(last_line); // simply replace line
            return(false); // no action needed
         }else{
            // line is far off or completely missing and last_line doesn't help also
            // make a completely new line at Bid
            placeLine(Bid);
            return(true);
         }
      }
      return(true);
   }else{
      return(false);
   }
}

/**
* manage all the entry order placement
*/
void trade(){
   double start;
   static int last_level;
   
   if (lineMoved()){
      closeOpenOrders(OP_SELLSTOP, magic);
      closeOpenOrders(OP_BUYSTOP, magic);
   }
   start = getLine();
   
   // calculate global variable level here // FIXME: global variable side-effect hell.
   level = getNumOpenOrders(OP_BUY, magic) - getNumOpenOrders(OP_SELL, magic);
   
   if (running){
      // are we flat?
      if (level == 0){
         if (direction == SHORT && Ask > start){
            if (getNumOpenOrders(OP_SELLSTOP, magic) != 2){
               closeOpenOrders(OP_SELLSTOP, magic);
            }else{
               moveOrders(Ask - start);
            }
            placeLine(Ask);
            start = Ask;
            plotBreakEven();
            if (sound_grid_trail != ""){
               PlaySound(sound_grid_trail);
            }
         }
         
         if (direction == LONG && Bid < start){
            if (getNumOpenOrders(OP_BUYSTOP, magic) != 2){
               closeOpenOrders(OP_BUYSTOP, magic);
            }else{
               moveOrders(Bid - start);
            }
            placeLine(Bid);
            start = Bid;
            plotBreakEven();
            if (sound_grid_trail != ""){
               PlaySound(sound_grid_trail);
            }
         }
         
         // make sure first long orders are in place
         if (direction == BIDIR || direction == LONG){
            longOrders(start);
         }
         
         // make sure first short orders are in place
         if (direction == BIDIR || direction == SHORT){
            shortOrders(start);
         }
      }
   
      // are we already long?
      if (level > 0){
         // make sure the next long orders are in place
         longOrders(start);
      }

      // are we short?
      if (level < 0){
         // make sure the next short orders are in place
         shortOrders(start);
      }
      
      // we have two different models how to move the grid line.
      // If we are *not* flat we can snap it to the nearest grid level,
      // ths is better for handling situations where the order is triggered 
      // by the exact pip and price is immediately reversing.
      // If we are currently flat we *must* move it only when we have reached 
      // it *exactly*, because otherwise this would badly interfere with 
      // the trailing of the grid in the unidirectional modes. Also in 
      // bidirectional mode this would have some unwanted effects.
      if (level != 0){
         // snap to grid
         if (Ask + (pip * stop_distance / 6) >= start + stop_distance*pip){
            jumpGrid(1);
         }
      
         // snap to grid
         if (Bid - (pip * stop_distance / 6) <= start - stop_distance*pip){
            jumpGrid(-1);
         }
      }else{   
         // grid reached exactly
         if (Ask  >= start + stop_distance*pip){
            jumpGrid(1);
         }
         
         // grid reached exactly
         if (Bid  <= start - stop_distance*pip){
            jumpGrid(-1);
         }
      }
      
      // alert on level change (order triggered, not line moved)
      if (level != last_level){
         if (sound_order_triggered != ""){
            PlaySound(sound_order_triggered);
         }
         last_level = level;
      }
      
   }else{ // not running
      placeLine(Bid);
   }
}

/**
* move the line 1 stop_didtance up or down.
* 1 means up, -1 means down.
*/
void jumpGrid(int dir){
   placeLine(getLine() + pip * stop_distance * dir);
   if (sound_grid_step != ""){
      PlaySound(sound_grid_step);
   }
}

/**
* do we need to place a new entry order at this price?
* This is done by looking for a stoploss below or above the price
* where=-1 searches for stoploss below, where=1 for stoploss above price
* return false if there is already an order (open or pending)
*/ 
bool needsOrder(double price, int where){
   //return(false);
   int i;
   int total = OrdersTotal();
   int type;
   // search for a stoploss at exactly one grid distance away from price
   for (i=0; i<total; i++){
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      type = OrderType();
      if (where < 0){ // look only for buy orders (stop below)
         if (OrderMagicNumber() == magic && (type == OP_BUY || type == OP_BUYSTOP)){
            if (isEqualPrice(OrderStopLoss(), price + where * pip * stop_distance)){
               return(false);
            }
         }
      }
      if (where > 0){ // look only for sell orders (stop above)
         if (OrderMagicNumber() == magic && (type == OP_SELL || type == OP_SELLSTOP)){
            if (isEqualPrice(OrderStopLoss(), price + where * pip * stop_distance)){
               return(false);
            }
         }
      }
   }
   return(true);
}

/**
* Make sure there are the next two long orders above start in place.
* If they are already there do nothing, else replace the missing ones.
*/
void longOrders(double start){
   double a = start + stop_distance * pip;
   double b = start + 2 * stop_distance * pip;
   if (needsOrder(a, -1)){
      buyStop(lots, a, start, 0, magic, comment);
   }
   if (needsOrder(b, -1)){
      buyStop(lots, b, a, 0, magic, comment);
   }
}

/**
* Make sure there are the next two short orders below start in place.
* If they are already there do nothing, else replace the missing ones.
*/
void shortOrders(double start){
   double a = start - stop_distance * pip;
   double b = start - 2 * stop_distance * pip;
   if (needsOrder(a, 1)){
      sellStop(lots, a, start, 0, magic, comment);
   }
   if (needsOrder(b, 1)){
      sellStop(lots, b, a, 0, magic, comment);
   }
}

/**
* move all entry orders by the amount of d
*/
void moveOrders(double d){
   int i;
   for(i=0; i<OrdersTotal(); i++){
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      if (OrderMagicNumber() == magic){
         if (MathAbs(OrderOpenPrice() - getLine()) > 3 * stop_distance * pip){
            orderDeleteReliable(OrderTicket());
         }else{
            orderModifyReliable(
               OrderTicket(),
               OrderOpenPrice() + d,
               OrderStopLoss() + d,
               0,
               0,
               CLR_NONE
            );
         }
      }
   }
}

void info(){
   double floating;
   double pb, lp, tp;
   static int last_ticket;
   static datetime last_be_plot = 0; 
   int ticket;
   string dir;
   
   OrderSelect(OrdersHistoryTotal()-1, SELECT_BY_POS, MODE_HISTORY);
   ticket = OrderTicket();
   
   if (ticket != last_ticket){
      // history changed, need to recalculate realized profit
      realized = getProfitRealized(magic);
      last_ticket = ticket;
      
      // enforce a new break-even arrow plot immediately
      last_be_plot = 0;
   }
   
   floating = getProfit(magic);
   
   // the variable realized is the total realized of all time. 
   // the MT4-global variable _realized is a snapshot of this value when 
   // the EA was reset the last time. The difference is what we made
   // during the current cycle. Add floating to it and we have the 
   // profit of the current cycle.
   cycle_total_profit = realized - getGlobal("realized") + floating;
   
   if (running == false){
      dir = "trading stopped";
   }else{
      switch(direction){
         case LONG: 
            dir = "trading long";
            break;
         case SHORT: 
            dir = "trading short";
            break;
         default: 
            dir = "trading both directions";
      }
   }
   
   int level_abs = MathAbs(getNumOpenOrders(OP_BUY, magic) - getNumOpenOrders(OP_SELL, magic));
   stop_value = MarketInfo(Symbol(), MODE_TICKVALUE) * lots * stop_distance * points_per_pip;
   
   Comment("\n" + SP + name + magic + ", " + dir +
           "\n" + SP + "1 pip is " + DoubleToStr(pip, Digits) + " " + Symbol6() +
           "\n" + SP + "stop distance: " + stop_distance + " pip, lot-size: " + DoubleToStr(lots, 2) +
           "\n" + SP + "every stop equals " + DoubleToStr(stop_value, 2) + " " + AccountCurrency() +
           "\n" + SP + "realized: " + DoubleToStr(realized - getGlobal("realized"), 2) + "  floating: " + DoubleToStr(floating, 2) +
           "\n" + SP + "profit: " + DoubleToStr(cycle_total_profit, 2) + " " + AccountCurrency() + "  current level: " + level_abs +
           "\n" + SP + "auto-tp: " + auto_tp + " levels (" + DoubleToStr(auto_tp_price, Digits) + ", " + DoubleToStr(auto_tp_profit, 2) + " " + AccountCurrency() + ")");

   if (last_be_plot == 0 || TimeCurrent() - last_be_plot > 300){ // every 5 minutes
      plotBreakEven();
      last_be_plot = TimeCurrent();
   }

   // If you put a text object (not a label!) with the name "profit",  
   // anywhere on the chart then this can be used as a profit calculator.
   // The following code will find the position of this text object 
   // and calculate your profit, should price reach this position
   // and then write this number into the text object. You can
   // move it around on the chart to get profit projections for
   // any price level you want. 
   if (ObjectFind("profit") != -1){
      pb = getPyramidBase();
      lp = ObjectGet("profit", OBJPROP_PRICE1);
      if (pb ==0){
         if (direction == SHORT){
            pb = getLine() - stop_distance * pip;
         }
         if (direction == LONG){
            pb = getLine() + stop_distance * pip;
         }
         if (direction == BIDIR){
            if (lp < getLine()){
               pb = getLine() - stop_distance * pip;
            }
            if (lp >= getLine()){
               pb = getLine() + stop_distance * pip;
            }
         }
      }
      tp = getTheoreticProfit(MathAbs(lp - pb));
      ObjectSetText("profit", "ฏฏฏ " + DoubleToStr(MathRound(realized - getGlobal("realized") + tp), 0) + " " + AccountCurrency() + " profit projection ฏฏฏ");
   }
   
}

/**
* Plot an arrow. Default is the price-exact dash symbol
* This function might be moved into common_functions soon
*/
string arrow(string name="", double price=0, datetime time=0, color clr=Red, int arrow_code=4){
   if (time == 0){
      time = TimeCurrent();
   }
   if (name == ""){
      name = "arrow_" + time;
   }
   if (price == 0){
      price = Bid;
   }
   if (ObjectFind(name) < 0){
      ObjectCreate(name, OBJ_ARROW, 0, time, price);
   }else{
      ObjectSet(name, OBJPROP_PRICE1, price);
      ObjectSet(name, OBJPROP_TIME1, time);
   }
   ObjectSet(name, OBJPROP_ARROWCODE, arrow_code);
   ObjectSet(name, OBJPROP_SCALE, 1);
   ObjectSet(name, OBJPROP_COLOR, clr);
   ObjectSet(name, OBJPROP_BACK, true);
   return(name);
}

/**
* plot the break even price into the chart
*/
void plotBreakEvenArrow(string arrow_name, double price){
   arrow(arrow_name + TimeCurrent(), price, 0, clr_breakeven_level);
}


/**
* plot the break-even Point (only a rough estimate plusminus less than one stop_distance,
* it will be most inaccurate just before hitting a stoploss (last trade negative).
* and this will be more obvious at the beginning of a new cycle when losses are still small
* and break even steps increments are still be big.
*
* Side effects: This function will also calculate auto-tp price and profit.
*
* FIXME: This whole break even calculation sucks comets through drinking straws!
* FIXME: Isn't there a more elegant way to calculate break even?
*/
void plotBreakEven(){
   double base = getPyramidBase();
   double be = 0;
   
   // loss is roughly the amount of realized stop hits. But I can't use this number
   // directly because after resuming a paused pyramid this number is wrong. So
   // I have to estimate it with the (always accurate) total profit and the current
   // distance from base. In mose cases the outcome of this calculation is equal
   // to the realized losses as displayed on the screen, only when resuming a pyramid 
   // it will differ and have the value it would have if the pyramid never had been paused.
   double distance = MathAbs(Close[0] - base);
   if ((level > 0 && Close[0] < base) || (level < 0 && Close[0] > base) || level == 0){
      distance = 0;
   }
   double loss = -(cycle_total_profit - getTheoreticProfit(distance));

   // this value should always be positive 
   // or 0 (or slightly below (rounding error)) in case we have a fresh pyramid.
   // If it is not positive (no loss yet) then we dont need to plot break even.
   if (loss <= 0 || !running){
      auto_tp_price = 0;
      auto_tp_profit = 0;
      return(0);
   }
   
   if (direction == LONG){
      if (base==0){
         base = getLine() + stop_distance * pip;
      }
      be = base + getBreakEven(loss);
      plotBreakEvenArrow("breakeven_long", be);
      auto_tp_price = be + pip * stop_distance * auto_tp;
      auto_tp_profit = getTheoreticProfit(MathAbs(auto_tp_price - base)) - loss;
   }
   
   if (direction == SHORT){
      if (base==0){
         base = getLine() - stop_distance * pip;
      }
      be = base - getBreakEven(loss);
      plotBreakEvenArrow("breakeven_short", be);
      auto_tp_price = be - pip * stop_distance * auto_tp;
      auto_tp_profit = getTheoreticProfit(MathAbs(auto_tp_price - base)) - loss;
   }
   
   if (direction == BIDIR){
      if (base == 0){
         base = getLine() + stop_distance * pip;
         plotBreakEvenArrow("breakeven_long", base + getBreakEven(loss));
         base = getLine() - stop_distance * pip;
         plotBreakEvenArrow("breakeven_short", base - getBreakEven(loss));
         auto_tp_price = 0;
         auto_tp_profit = 0;
      }else{
         if (getLotsOnTableSigned(magic) > 0){
            be = base + getBreakEven(loss);
            plotBreakEvenArrow("breakeven_long", be);
            auto_tp_price = be + pip * stop_distance * auto_tp;
            auto_tp_profit = getTheoreticProfit(MathAbs(auto_tp_price - base)) - loss;
         }else{
            be = base - getBreakEven(loss);
            plotBreakEvenArrow("breakeven_short", be);
            auto_tp_price = be - pip * stop_distance * auto_tp;
            auto_tp_profit = getTheoreticProfit(MathAbs(auto_tp_price - base)) - loss;
         }
      }
   }
   
   if (auto_tp < 1){
      auto_tp_price = 0;
      auto_tp_profit = 0;
   }
}


/**
* return the entry price of the first order of the pyramid.
* return 0 if we are flat.
*/
double getPyramidBase(){
   double d, max_d, sl;
   int i;
   int type=-1;
   
   // find the stoploss that is farest away from current price
   // we cannot just use the order open price because we might
   // be in resume mode and then all trades would be opened at
   // the same price. the only thing that works reliable is 
   // looking at the stoplossses
   for (i=0; i<OrdersTotal(); i++){
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      if (OrderMagicNumber() == magic && OrderType() < 2){
         d = MathAbs(Close[0] - OrderStopLoss());
         if (d > max_d){
            max_d = d;
            sl = OrderStopLoss();
            type = OrderType();
         }
      }
   }
   
   if (type == OP_BUY){
      return(sl + pip * stop_distance);
   }
   
   if (type == OP_SELL){
      return(sl - pip * stop_distance);
   }
   
   return(0);
}

double getPyramidBase1(){
   int i;
   double pmax = -999999;
   double base = 0;
   for (i=0; i<OrdersTotal(); i++){
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      if (OrderMagicNumber() == magic && OrderType() < 2){
         if (OrderProfit() > pmax){
            base = OrderOpenPrice();
            pmax = OrderProfit();
         }
      }
   }
   return(base);
}

/**
* return the floating profit that would result if
* price would be the specified distance away from
* the base of the pyramid
*/ 
double getTheoreticProfit(double distance){
   int n = MathFloor(distance / (stop_distance * pip));
   double remain = distance - n * stop_distance * pip;
   int mult = n * (n + 1) / 2;
   double profit = MarketInfo(Symbol(), MODE_TICKVALUE) * lots * stop_distance * points_per_pip * mult;
   profit = profit + MarketInfo(Symbol(), MODE_TICKVALUE) * lots * (remain/Point) * (n + 1);
   return(profit);
}

/**
* return the price move relative to base required to compensate realized losses
* FIXME: This algorithm does not qualify as "elegant", not even remotely. 
*/
double getBreakEven(double loss){
   double i = 0;
   
   while(true){
      if (getTheoreticProfit(pip * i) > loss){
         break;
      }
      i += stop_distance;
   }
   
   i -= stop_distance;
   while(true){
      if (getTheoreticProfit(pip * i) > loss){
         break;
      }
      i += 0.1;
   }

   return(pip * i);
}

int start(){
   static int numbars;
   onTick();
   if (Bars == numbars){
      return(0);
   }
   numbars = Bars;
   onOpen();
   return(0);
}

void setGlobal(string key, double value){
   GlobalVariableSet(name + magic + "_" + key, value);
}

double getGlobal(string key){
   return(GlobalVariableGet(name + magic + "_" + key));
}

ไม่มีความคิดเห็น:

แสดงความคิดเห็น