//+------------------------------------------------------------------+
//|                                              BLSH_Hybrid ver 1.0 |
//|                           Copyright © 2006, Automatic Forex, LLC |
//|                                             http://autoforex.biz |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, 2007 Automatic Forex, LLC"
#property link      "http://autoforex.biz"

// For trading MINI accounts

// Trades bidirectionally when a trend is not detected.
// and in the indicated direction when a trend is detected.

// This version is maintained by Robert C. Cochran (Bob).
// Key trading tactics provided by pipscooper.
// Original code developed by EMSJOFLO and pipscooper.
// Some R&D contributions provided by techinvest.
// Bob's contributions include:
//   - General code cleanup and removal of inefficiencies
//   - Eequity pop tracking
//   - Refinement of the money management
//   - The breakout/trend logic
//   - The "ghost note" logic
//   - MQL-II and MQ4 plus mini/standard version compatibility
//   - Closure of individual losers
// Many of Bob's contributions originated in testing and subsequent
// suggestions by Automatic Forex forum members, which resulted in
// implementation adjustments by Bob.

//+------------------------------------------------------------------+
//|              External Variables                                  |
//+------------------------------------------------------------------+

extern int    BigThreshold        =  20;
extern int    SmallThreshold      =   5;
extern double ProfitMultiple      =   1.001;
extern double LoRisk              =   0.003;
extern double HiRisk              =   0.03;
extern int    Slippage            =   3;
extern double Lots                =   0.1;
extern bool   MoneyManagement     =   true;
extern bool   AccountIsMini       =   true;
extern bool   StopAfterNoTrades   =   false;
extern double RockBottomEquityPct =   0.5;
extern int    EMAperiod           =   5;
extern int    EMApipInterval      =  10;
extern int    LessPips            =   4;
extern int    MorePips            = 100;

//+------------------------------------------------------------------+
//|              Internal Variables                                  |
//+------------------------------------------------------------------+

double RiskVar;
int    BuyProfitTarget, SellProfitTarget;
double LastPrice1=0, LastPrice2=0, Anchor1=0, Anchor2=0;
int i;
double MinLots, MaxLots, UseLots;
string OrigBal;     double valOrigBal;
string EquityFlag;  int    valEquityFlag;
string GravyProfit; double valGravyProfit;
string CurrBalance; double valCurrBalance;
int    NumBuys, NumSells;
bool   CloseAll;
double SymbolPL, EquityExit;
double TenEMA0, TenEMA2;
double BiggestLoser;
int    LoserTicket;

//+------------------------------------------------------------------+
//|              Expert Initialization                               |
//+------------------------------------------------------------------+
int init()
{
  LastPrice1 = Bid;
  LastPrice2 = Bid;
  Anchor1 = (Ask+Bid)/2;
  Anchor2 = (Ask+Bid)/2;
  return(0);
}

//+------------------------------------------------------------------+
//|                   Expert start                                   |
//+------------------------------------------------------------------+

int start()
{

  // Specify a name for the global variable that tracks gravy profit.
  OrigBal = AccountNumber()+"_"+Symbol()+"_"+Period()+"_OrigBal";

  // Define the variable if it doesn't already exist.
  if (!GlobalVariableCheck(OrigBal)) GlobalVariableSet(OrigBal, AccountBalance());

  // Set the value.
  valOrigBal = GlobalVariableGet(OrigBal);


  // Specify a name for the global Equity flag variable.
  EquityFlag = AccountNumber()+"_"+Symbol()+"_"+Period()+"_EquityFlag";

  // Define the variable if it doesn't already exist.
  if (!GlobalVariableCheck(EquityFlag)) GlobalVariableSet(EquityFlag, 0);

  // Get a value.
  valEquityFlag = GlobalVariableGet(EquityFlag);


  // Specify a name for the global variable that tracks Gravy profit.
  GravyProfit = AccountNumber()+"_"+Symbol()+"_"+Period()+"_GravyProfit";

  // Define the variable if it doesn't already exist.
  if (!GlobalVariableCheck(GravyProfit)) GlobalVariableSet(GravyProfit, 0.0);

  // Get a value.
  valGravyProfit = GlobalVariableGet(GravyProfit);


  // Specify a name for the global variable that tracks the current balance.
  CurrBalance = AccountNumber()+"_"+Symbol()+"_"+Period()+"_CurrBalance";

  // Define the variable if it doesn't already exist.
  if (!GlobalVariableCheck(CurrBalance)) GlobalVariableSet(CurrBalance, 0.0);

  // Get a value.
  valCurrBalance = GlobalVariableGet(CurrBalance);

//+------------------------------------------------------------------+
//|                      Equity Pop Time !!!                         |   
//+------------------------------------------------------------------+  


  if (CloseAll)
  {
    for(i = OrdersTotal()-1; i >= 0; i--)
    {
      OrderSelect(i,SELECT_BY_POS,MODE_TRADES);

      if (OrderSymbol() == Symbol())
      {
        if (OrderType() == OP_BUY && OrderProfit() < 0) 
        {
          Comment("In grid closure mode.  Closing a losing buy trade...");
	       OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,White);
        }    

        if (OrderType() == OP_SELL && OrderProfit() < 0)
        {
          Comment("In grid closure mode.  Closing a losing sell trade...");
          OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,White);
        }
      }
    }

    for(i = OrdersTotal()-1; i >= 0; i--)
    {
      OrderSelect(i,SELECT_BY_POS,MODE_TRADES);

      if (OrderSymbol() == Symbol())
      {
        if (OrderType() == OP_BUY && OrderProfit() >= 0) 
        {
          Comment("In grid closure mode.  Closing a winning buy trade...");
	       OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,White);
        }    

        if (OrderType() == OP_SELL && OrderProfit() >= 0)
        {
          Comment("In grid closure mode.  Closing a winning sell trade...");
          OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,White);
        }
      }
    }
    GlobalVariableSet(GravyProfit, 0);
    GlobalVariableSet(EquityFlag, 0);
  }

  if (valGravyProfit == 0) GlobalVariableSet(OrigBal, AccountBalance());

  //+------------------------------------------------------------------+
  //|                     Spread Checks & Pip Values                   |   
  //+------------------------------------------------------------------+ 

  if (Bid > LastPrice1) LastPrice1 = Bid;
  if (Ask < LastPrice1) LastPrice1 = Ask;
  if (Bid > LastPrice2) LastPrice2 = Bid;
  if (Ask < LastPrice2) LastPrice2 = Ask;

  NumBuys      = 0;
  NumSells     = 0;
  SymbolPL     = 0.0;
  BiggestLoser = 0.0;
  LoserTicket  = 0;

  for(i = 0; i < OrdersTotal(); i++)
  {
    OrderSelect(i,SELECT_BY_POS,MODE_TRADES);

    if (OrderSymbol() == Symbol()) 
    {
      SymbolPL += OrderProfit();

      if (OrderProfit() < BiggestLoser)
      {
        BiggestLoser = OrderProfit();
        LoserTicket  = OrderTicket();
      }

      if (OrderType() == OP_BUY)  NumBuys++;
      if (OrderType() == OP_SELL) NumSells++;
    }   
  }

  if (NumBuys+NumSells == 0)
  {
    Comment("There are no trades open.");
  
    if (StopAfterNoTrades) return(0);

    CloseAll = false;
  }
  else
  if (NumBuys+NumSells >  0              &&
      AccountBalance() != valCurrBalance &&
      valEquityFlag  == 1)
  {
    if (AccountBalance() < valCurrBalance)
      valGravyProfit = 0;
    else
      valGravyProfit = valGravyProfit + (AccountBalance() - valCurrBalance);

    GlobalVariableSet(GravyProfit, valGravyProfit);
    GlobalVariableSet(EquityFlag, 0);
  }

  GlobalVariableSet(CurrBalance, AccountBalance());


  TenEMA0 = iMA(NULL, NULL, EMAperiod, 0, MODE_EMA, PRICE_CLOSE, 0);
  TenEMA2 = iMA(NULL, NULL, EMAperiod, 0, MODE_EMA, PRICE_CLOSE, 2);

  //+------------------------------------------------------------------+
  //|                      Money Management                            |   
  //+------------------------------------------------------------------+   
   
  if (MoneyManagement)
  {
    if (TenEMA0 >= TenEMA2 + EMApipInterval*Point ||
        TenEMA0 <= TenEMA2 - EMApipInterval*Point)
    {
      RiskVar = HiRisk;
    }
    else
    {
      RiskVar = LoRisk;
    }

    if (AccountIsMini)
    {
      MinLots =   0.01;
      MaxLots =  50.0;
    } 
    else
    {   
      MinLots =   0.01;
      MaxLots = 100.0;
      RiskVar /= 10.0;
    }

    UseLots = MinLots * valOrigBal * RiskVar;
    UseLots = StrToDouble(DoubleToStr(UseLots, 2));
    if (UseLots < MinLots) UseLots = MinLots;
    if (UseLots > MaxLots) UseLots = MaxLots;
  } 
  else UseLots = Lots;
    
  EquityExit = (valOrigBal * ProfitMultiple) - valOrigBal;


  if (!CloseAll &&
       valGravyProfit + SymbolPL >= EquityExit)
  {
    CloseAll = true; 
    return(0);
  }
   
  //+------------------------------------------------------------------+
  //|                      Trade Function                              |   
  //+------------------------------------------------------------------+  
  
  if (TenEMA0 >= TenEMA2 + EMApipInterval*Point)
  { BuyProfitTarget = MorePips; }
  else
  { BuyProfitTarget = LessPips; }

  if (TenEMA0 <= TenEMA2 - EMApipInterval*Point)
  { SellProfitTarget = MorePips; }
  else
  { SellProfitTarget = LessPips; }

  for(i = 0; i <OrdersTotal(); i++)
  {
    OrderSelect(i,SELECT_BY_POS,MODE_TRADES);

    if (OrderSymbol() == Symbol())
    {
      //+------------------------------------------------------------------+
      //|                      Manage Our Open Buy Orders                  |   
      //+------------------------------------------------------------------+  
      
      if (OrderType() == OP_BUY)
      {
        if (BiggestLoser < 0.0                         &&
            valGravyProfit + BiggestLoser > EquityExit &&
            OrderTicket() == LoserTicket)
        {
          Comment("Closing a losing buy trade...");
          OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,LightBlue);
          GlobalVariableSet(EquityFlag, 1);
          return(0);
        }

        if (Bid - OrderOpenPrice() >= BuyProfitTarget*Point)
        {
          Comment("Closing a winning buy trade...");
          OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,LightBlue);
          GlobalVariableSet(EquityFlag, 1);
          return(0);
        }
      }

      //+------------------------------------------------------------------+
      //|                      Manage Our Open Sell Orders                 |   
      //+------------------------------------------------------------------+
      
      if (OrderType() == OP_SELL)
      {
        if (BiggestLoser < 0.0                         &&
            valGravyProfit + BiggestLoser > EquityExit &&
            OrderTicket() == LoserTicket)
        {
          Comment("Closing a losing sell trade...");
          OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,LightPink);
          GlobalVariableSet(EquityFlag, 1);
          return(0);
        }

        if (OrderOpenPrice() - Ask >= SellProfitTarget*Point)
        {
          Comment("Closing a sell trade...");
          OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,LightPink);
          GlobalVariableSet(EquityFlag, 1);
          return(0);
        }
      }
    }
  }  

  if (AccountEquity() < RockBottomEquityPct * valOrigBal) return(0);

  //+------------------------------------------------------------------+
  //|             Price Moving Down Within Strong Uptrend              |   
  //+------------------------------------------------------------------+  
  
  if (LastPrice1 <= Anchor1 - BigThreshold * Point)
  { 
    Anchor1 = LastPrice1;

    if (TenEMA0 >= TenEMA2 + EMApipInterval*Point)
    {
      OrderSend(Symbol(),OP_BUY,UseLots,Ask,Slippage,0,0,"BLSH_EquityPop",0,0,Blue);
      return(0);
    }
  } 

  //+------------------------------------------------------------------+
  //|                  Price Moving Down In No Trend                   |
  //+------------------------------------------------------------------+  

  if (LastPrice2 <= Anchor2 - SmallThreshold * Point)
  { 
    Anchor2 = LastPrice2;

    if (TenEMA0 < TenEMA2 + EMApipInterval*Point &&
        TenEMA0 > TenEMA2 - EMApipInterval*Point)
    {
      OrderSend(Symbol(),OP_BUY,UseLots,Ask,Slippage,0,0,"BLSH_EquityPop",0,0,Blue);
      return(0);
    }
  } 

  //+------------------------------------------------------------------+
  //|             Price Moving Up Within Strong Downtrend              |   
  //+------------------------------------------------------------------+  

  if (LastPrice1 >= Anchor1 + BigThreshold * Point) 
  {
    Anchor1 = LastPrice1;

    if (TenEMA0 <= TenEMA2 - EMApipInterval*Point)
    {
      OrderSend(Symbol(),OP_SELL,UseLots,Bid,Slippage,0,0,"BLSH_EquityPop",0,0,Red);
      return(0);
    }
  } 

  //+------------------------------------------------------------------+
  //|                  Price Moving Up In No Trend                     |
  //+------------------------------------------------------------------+  

  if (LastPrice2 >= Anchor2 + SmallThreshold * Point) 
  {
    Anchor2 = LastPrice2;

    if (TenEMA0 < TenEMA2 + EMApipInterval*Point &&
        TenEMA0 > TenEMA2 - EMApipInterval*Point)
    {
      OrderSend(Symbol(),OP_SELL,UseLots,Bid,Slippage,0,0,"BLSH_EquityPop",0,0,Red);
      return(0);
    }
  } 


  //+------------------------------------------------------------------+
  //|                      Print Info to Chart                         |   
  //+------------------------------------------------------------------+          
         
  Comment("Balance: ", AccountBalance(), ",   Equity: ", AccountEquity(), ",   Lots: ", UseLots,
        ",   Anchor 1 Price: ", Anchor1, ",   Anchor 2 Price: ", Anchor2,
        ",   Last Price 1: ", LastPrice1, ",   Last Price 2: ", LastPrice2,
        ",   Num Buys: ", NumBuys, ",   Num Sells: ", NumSells,
        ",   Dollar Target: ", EquityExit, ",   SymbolPL: ", SymbolPL,
        ",   Gravy: " , valGravyProfit, ",   Gravy + PL: ", valGravyProfit + SymbolPL,
        "\nGravy + Biggest Loser: ", valGravyProfit + BiggestLoser,
        "    Orig Bal: ", valOrigBal,
        ",   BuyProfitTarget: ", BuyProfitTarget, ",   SellProfitTarget: ", SellProfitTarget,
        ",   Biggest Loser: ", BiggestLoser, ",   Ticket: ", LoserTicket);

  return(0);
}

