//+------------------------------------------------------------------+
//|                                             Art_Phantom_Full_QQE |
//+------------------------------------------------------------------+
/*


Modified by hopfi2kme.com, December 2010

Attach to any chart, any timeframe. Do not attach to more than one
chart.

These are the pairs we trade:

For InterbankFX
---------------
Group 1, The Phantom Buys
6.  EURJPY

Group 2, The Phantom Sells
7.  EURUSD
8.  USDJPY

Initially, buy the phantom buy group of pairs and sell the phantom-sell
group of pairs.

Every 30 min, add a real trade of every winning phantom pair if the pair is
EURJPY, EURUSD, USDJPY, but only76 if all previous trades for that pair 
are winners.

Close all when current equity exceeds ProfitPct above last flat equity.

*/

#define QQEFile       "QQE ADV"

//+------------------------------------------------------------------+
//|              External Variables                                  |
//+------------------------------------------------------------------+

extern bool   Bailout = false;

extern int    Slippage         =       3;
extern int    MiniSize         =   10000;
extern int    StdSize          =  100000;

extern int GBPUSDidx = 0;
extern int EURGBPidx = 1;
extern int GBPJPYidx = 2;
extern int USDCHFidx = 3;
extern int NZDUSDidx = 4;
extern int AUDJPYidx = 5;
extern int EURJPYidx = 6;

extern int EURUSDidx = 7;
extern int USDJPYidx = 8;
extern int AUDUSDidx = 9;
extern int NZDJPYidx = 10;
extern int GBPCHFidx = 11;
extern int CHFJPYidx = 12;
extern int EURCHFidx = 13;

extern int Sunday    = 0;
extern int Monday    = 1;
extern int Tuesday   = 2;
extern int Wednesday = 3;
extern int Thursday  = 4;
extern int Friday    = 5;
extern int Saturday  = 6;

extern bool   UserTradingAllowed   = true;
extern bool   StopAfterNoTrades    = false;
extern bool   UseSmallestLot       = false;

extern double MaxMarginToUse      =     0.2; // Maximum percent of margin to commit to each trade.
extern double Lots                =     0.1;
extern double ProfitPct           =     1.0;
extern double MaxMiniProfit       =  1000.0;
extern double MaxStdProfit        = 10000.0;

extern string info0____________   = "----- QQE Advance Parameters -----";
extern int QQE_TrendTimeframe     = PERIOD_H4;
extern int QQE_EntryTimeframe     = PERIOD_M15;
extern int QQE_SF                 = 3;
extern int QQE_RSI_Period         = 8;
extern int QQE_WP                 = 3;

extern string info1____________   = "----- DrawDown handling ----------";
extern int Reduce_PP_afterMaxTrades = 12;
extern int Reduce_PP_to           = 0.0;
extern int SL_per_position        = 50;
extern int MagicNumber            =  777111;


//+------------------------------------------------------------------+
//|              Internal Variables                                  |
//+------------------------------------------------------------------+

string trend[3] = { "LONG", "SHORT", "RANGING" };
int i, j;
int OrderSendResult;
int Leverage;
int NumBuys, NumSells;
int TotalTrades;
int AccountTypeVal;

int GBPUSDbuys, GBPUSDsells;
int EURGBPbuys, EURGBPsells;
int GBPJPYbuys, GBPJPYsells;
int USDCHFbuys, USDCHFsells;
int NZDUSDbuys, NZDUSDsells;
int AUDJPYbuys, AUDJPYsells;
int EURJPYbuys, EURJPYsells;

int EURUSDbuys, EURUSDsells;
int USDJPYbuys, USDJPYsells;
int AUDUSDbuys, AUDUSDsells;
int NZDJPYbuys, NZDJPYsells;
int GBPCHFbuys, GBPCHFsells;
int CHFJPYbuys, CHFJPYsells;
int EURCHFbuys, EURCHFsells;

bool AccountIsMini;
bool CloseNextLoser;
bool CloseAll;
bool BidsHaveChanged = false;
bool Group1LongGroup2Short, Group1ShortGroup2Long;

string AccountTypeString;
string LastFlatBal;           double valLastFlatBal;
string LastFlatEq;            double valLastFlatEq;
string LowestMarginLevel;     double valLowestMarginLevel;
string LargestFloatingLoss;   double valLargestFloatingLoss;
string MaxFloatingDrawdown;   double valMaxFloatingDrawdown;

string GBPUSDadded; bool valGBPUSDadded;
string EURGBPadded; bool valEURGBPadded;
string GBPJPYadded; bool valGBPJPYadded;
string USDCHFadded; bool valUSDCHFadded;
string NZDUSDadded; bool valNZDUSDadded;
string AUDJPYadded; bool valAUDJPYadded;
string EURJPYadded; bool valEURJPYadded;

string EURUSDadded; bool valEURUSDadded;
string USDJPYadded; bool valUSDJPYadded;
string AUDUSDadded; bool valAUDUSDadded;
string NZDJPYadded; bool valNZDJPYadded;
string GBPCHFadded; bool valGBPCHFadded;
string CHFJPYadded; bool valCHFJPYadded;
string EURCHFadded; bool valEURCHFadded;

string GBPUSDsym;
string EURGBPsym;
string GBPJPYsym;
string USDCHFsym;
string NZDUSDsym;
string AUDJPYsym;
string EURJPYsym;

string EURUSDsym;
string USDJPYsym;
string AUDUSDsym;
string NZDJPYsym;
string GBPCHFsym;
string CHFJPYsym;
string EURCHFsym;

string CommentString;

string SymbolArray[14];

double MaxLots;
double MinLots;
double UseLots, TotalLots, BuyLots, SellLots;
double phantomEAPL, phantomBuyPL, phantomSellPL, PairOverallPL, EAPL, BuyPL, SellPL, EquityExit;
double PercentMarginLevel;
double DollarProfitTarget;
double MaxMarginVar;
double Investment;

// PL for real trades

double GBPUSDPL;
double EURGBPPL;
double GBPJPYPL;
double USDCHFPL;
double NZDUSDPL;
double AUDJPYPL;
double EURJPYPL;

double EURUSDPL;
double USDJPYPL;
double AUDUSDPL;
double NZDJPYPL;
double GBPCHFPL;
double CHFJPYPL;
double EURCHFPL;

// PL for phantom trades

double GBPUSD_PL;
double EURGBP_PL;
double GBPJPY_PL;
double USDCHF_PL;
double NZDUSD_PL;
double AUDJPY_PL;
double EURJPY_PL;

double EURUSD_PL;
double USDJPY_PL;
double AUDUSD_PL;
double NZDJPY_PL;
double GBPCHF_PL;
double CHFJPY_PL;
double EURCHF_PL;

double prevGBPUSDbid = 0.0;
double prevEURGBPbid = 0.0;
double prevGBPJPYbid = 0.0;
double prevUSDCHFbid = 0.0;
double prevNZDUSDbid = 0.0;
double prevAUDJPYbid = 0.0;
double prevEURJPYbid = 0.0;

double prevEURUSDbid = 0.0;
double prevUSDJPYbid = 0.0;
double prevAUDUSDbid = 0.0;
double prevNZDJPYbid = 0.0;
double prevGBPCHFbid = 0.0;
double prevCHFJPYbid = 0.0;
double prevEURCHFbid = 0.0;

double BiggestWinnerPL;
double BiggestWinnerLots;
int    BiggestWinnerTicket;
string BiggestWinnerType;
string BiggestWinnerSymbol;

double BiggestLoserPL;
double BiggestLoserLots;
int    BiggestLoserTicket;
string BiggestLoserType;
string BiggestLoserSymbol;

double BiggestPhantomWinnerPL;
string BiggestPhantomWinnerType;
string BiggestPhantomWinnerSymbol;

string strGBPUSDask; double GBPUSDask = 0.0, GBPUSDpoint, GBPUSDtickval;
string strEURGBPask; double EURGBPask = 0.0, EURGBPpoint, EURGBPtickval;
string strGBPJPYask; double GBPJPYask = 0.0, GBPJPYpoint, GBPJPYtickval;
string strUSDCHFask; double USDCHFask = 0.0, USDCHFpoint, USDCHFtickval;
string strNZDUSDask; double NZDUSDask = 0.0, NZDUSDpoint, NZDUSDtickval;
string strAUDJPYask; double AUDJPYask = 0.0, AUDJPYpoint, AUDJPYtickval;
string strEURJPYask; double EURJPYask = 0.0, EURJPYpoint, EURJPYtickval;

string strEURUSDbid; double EURUSDbid = 0.0, EURUSDpoint, EURUSDtickval;
string strUSDJPYbid; double USDJPYbid = 0.0, USDJPYpoint, USDJPYtickval;
string strAUDUSDbid; double AUDUSDbid = 0.0, AUDUSDpoint, AUDUSDtickval;
string strNZDJPYbid; double NZDJPYbid = 0.0, NZDJPYpoint, NZDJPYtickval;
string strGBPCHFbid; double GBPCHFbid = 0.0, GBPCHFpoint, GBPCHFtickval;
string strCHFJPYbid; double CHFJPYbid = 0.0, CHFJPYpoint, CHFJPYtickval;
string strEURCHFbid; double EURCHFbid = 0.0, EURCHFpoint, EURCHFtickval;

double PL_Array[14];
double TickvalArray[14];

//+------------------------------------------------------------------+
//|   Expert Advisor Initialization, executes only when the EA is    |
//|   first attached to a chart or on platform  restart.             |
//+------------------------------------------------------------------+

int init()
{
  Comment("Waiting for next tick...");
  SetGlobalVariableNames();
  InitGlobalVars();
  ResetPhantoms();

  return (0);
}

//+------------------------------------------------------------------+
//|    Expert Advisor start function, executes on each tick of the   |
//|    currecy pair it's attached to.                                |
//+------------------------------------------------------------------+

int start()
{
  if (Bailout || (!IsTesting() && !IsExpertEnabled()))
  {
    Comment("Expert is not enabled");

    return(0);
  }

  RefreshGlobalVars();
  GetAccountInfo();  
  SetSymbols();
  SetAccountType();
  SetLotSize();  
  Count_PL_Trades_Lots();
  SetExitTargets();

  BidsHaveChanged = 

    prevGBPUSDbid != 0.0 &&
    prevEURGBPbid != 0.0 &&
    prevGBPJPYbid != 0.0 &&
    prevUSDCHFbid != 0.0 &&
    prevNZDUSDbid != 0.0 &&
    prevAUDJPYbid != 0.0 &&
    prevEURJPYbid != 0.0 &&

    prevEURUSDbid != 0.0 &&
    prevUSDJPYbid != 0.0 &&
    prevAUDUSDbid != 0.0 &&
    prevNZDJPYbid != 0.0 &&
    prevGBPCHFbid != 0.0 &&
    prevCHFJPYbid != 0.0 &&
    prevEURCHFbid != 0.0 &&

    (prevGBPUSDbid != MarketInfo(GBPUSDsym, MODE_BID) ||
     prevEURGBPbid != MarketInfo(EURGBPsym, MODE_BID) ||
     prevGBPJPYbid != MarketInfo(GBPJPYsym, MODE_BID) ||
     prevUSDCHFbid != MarketInfo(USDCHFsym, MODE_BID) ||
     prevNZDUSDbid != MarketInfo(NZDUSDsym, MODE_BID) ||
     prevAUDJPYbid != MarketInfo(AUDJPYsym, MODE_BID) ||
     prevEURJPYbid != MarketInfo(EURJPYsym, MODE_BID) ||
     prevEURUSDbid != MarketInfo(EURUSDsym, MODE_BID) ||
     prevUSDJPYbid != MarketInfo(USDJPYsym, MODE_BID) ||
     prevAUDUSDbid != MarketInfo(AUDUSDsym, MODE_BID) ||
     prevNZDJPYbid != MarketInfo(NZDJPYsym, MODE_BID) ||
     prevGBPCHFbid != MarketInfo(GBPCHFsym, MODE_BID) ||
     prevCHFJPYbid != MarketInfo(CHFJPYsym, MODE_BID) ||
     prevEURCHFbid != MarketInfo(EURCHFsym, MODE_BID));

  CloseAllTradesIfNeeded();
  OpenPhantomTrades();
  CalcPhantomPL();
  AddIfNeeded();

  if (TotalTrades == 0)
  {
    if (AccountBalance() > valLastFlatBal)
    {
      valLastFlatBal = AccountBalance();
      GlobalVariableSet(LastFlatBal, valLastFlatBal);
    }

    if (AccountEquity() > valLastFlatEq)
    {
      valLastFlatEq = AccountEquity();
      GlobalVariableSet(LastFlatEq,  valLastFlatEq);
    }

    if (!IsExpertEnabled() || StopAfterNoTrades) return(0);

    CloseAll = false;
  }
  else if (TotalTrades >= Reduce_PP_afterMaxTrades ) {
   // maximum number of open trades to be reached to
   // reduced Profit Target to prevent a deadlock situation
   // and get away with BE
   ProfitPct = Reduce_PP_to;
  }

  if (!CloseAll && valLastFlatEq != 0.0 && AccountEquity()-valLastFlatEq > DollarProfitTarget)
  {
    CloseAll = true;
    ResetPhantoms();

    return(0);
  }

  ExamineMarginAndFloat();

  prevGBPUSDbid = MarketInfo(GBPUSDsym, MODE_BID);
  prevEURGBPbid = MarketInfo(EURGBPsym, MODE_BID);
  prevGBPJPYbid = MarketInfo(GBPJPYsym, MODE_BID);
  prevUSDCHFbid = MarketInfo(USDCHFsym, MODE_BID);
  prevNZDUSDbid = MarketInfo(NZDUSDsym, MODE_BID);
  prevAUDJPYbid = MarketInfo(AUDJPYsym, MODE_BID);
  prevEURJPYbid = MarketInfo(EURJPYsym, MODE_BID);

  prevEURUSDbid = MarketInfo(EURUSDsym, MODE_BID);
  prevUSDJPYbid = MarketInfo(USDJPYsym, MODE_BID);
  prevAUDUSDbid = MarketInfo(AUDUSDsym, MODE_BID);
  prevNZDJPYbid = MarketInfo(NZDJPYsym, MODE_BID);
  prevGBPCHFbid = MarketInfo(GBPCHFsym, MODE_BID);
  prevCHFJPYbid = MarketInfo(CHFJPYsym, MODE_BID);
  prevEURCHFbid = MarketInfo(EURCHFsym, MODE_BID);

  SinglePositionSL();
  PrintChartComments();
    
  return(0);
}

//+------------------------------------------------------------------+
//|          Assign values to global variable namestrings.           |
//+------------------------------------------------------------------+

void SetGlobalVariableNames()
{
  LowestMarginLevel = MagicNumber+"_LowestMarginLevel";
  LargestFloatingLoss = MagicNumber+"_LargestFloatingLoss";
  MaxFloatingDrawdown = MagicNumber+"_MaxFloatingDrawdown";

  LastFlatBal = MagicNumber+"_LastFlatBal";
  LastFlatEq  = MagicNumber+"_LastFlatEq";

  GBPUSDadded = MagicNumber+"_GBPUSDadded";
  EURGBPadded = MagicNumber+"_EURGBPadded";
  GBPJPYadded = MagicNumber+"_GBPJPYadded";
  USDCHFadded = MagicNumber+"_USDCHFadded";
  NZDUSDadded = MagicNumber+"_NZDUSDadded";
  AUDJPYadded = MagicNumber+"_AUDJPYadded";
  EURJPYadded = MagicNumber+"_EURJPYadded";

  EURUSDadded = MagicNumber+"_EURUSDadded";
  USDJPYadded = MagicNumber+"_USDJPYadded";
  AUDUSDadded = MagicNumber+"_AUDUSDadded";
  NZDJPYadded = MagicNumber+"_NZDJPYadded";
  GBPCHFadded = MagicNumber+"_GBPCHFadded";
  CHFJPYadded = MagicNumber+"_CHFJPYadded";
  EURCHFadded = MagicNumber+"_EURCHFadded";

  return(0);
}

//+------------------------------------------------------------------+
//|            Assign initial values to global variables.            |
//+------------------------------------------------------------------+

void InitGlobalVars()
{
  if (!GlobalVariableCheck(LowestMarginLevel)) GlobalVariableSet(LowestMarginLevel, 100000000.0);
  if (!GlobalVariableCheck(LargestFloatingLoss)) GlobalVariableSet(LargestFloatingLoss, 0.0);
  if (!GlobalVariableCheck(MaxFloatingDrawdown)) GlobalVariableSet(MaxFloatingDrawdown, 0.0);

  if (!GlobalVariableCheck(LastFlatBal)) GlobalVariableSet(LastFlatBal, AccountBalance());
  if (!GlobalVariableCheck(LastFlatEq)) GlobalVariableSet(LastFlatEq, AccountEquity());

  if (!GlobalVariableCheck(GBPUSDadded)) GlobalVariableSet(GBPUSDadded, false);
  if (!GlobalVariableCheck(EURGBPadded)) GlobalVariableSet(EURGBPadded, false);
  if (!GlobalVariableCheck(GBPJPYadded)) GlobalVariableSet(GBPJPYadded, false);
  if (!GlobalVariableCheck(USDCHFadded)) GlobalVariableSet(USDCHFadded, false);
  if (!GlobalVariableCheck(NZDUSDadded)) GlobalVariableSet(NZDUSDadded, false);
  if (!GlobalVariableCheck(AUDJPYadded)) GlobalVariableSet(AUDJPYadded, false);
  if (!GlobalVariableCheck(EURJPYadded)) GlobalVariableSet(EURJPYadded, false);

  if (!GlobalVariableCheck(EURUSDadded)) GlobalVariableSet(EURUSDadded, false);
  if (!GlobalVariableCheck(USDJPYadded)) GlobalVariableSet(USDJPYadded, false);
  if (!GlobalVariableCheck(AUDUSDadded)) GlobalVariableSet(AUDUSDadded, false);
  if (!GlobalVariableCheck(NZDJPYadded)) GlobalVariableSet(NZDJPYadded, false);
  if (!GlobalVariableCheck(GBPCHFadded)) GlobalVariableSet(GBPCHFadded, false);
  if (!GlobalVariableCheck(CHFJPYadded)) GlobalVariableSet(CHFJPYadded, false);
  if (!GlobalVariableCheck(EURCHFadded)) GlobalVariableSet(EURCHFadded, false);

  return(0);
}

//+------------------------------------------------------------------+
//|   Get global variable values via their namestring and assign the |
//|   stored values to the variables used in the EA's logic.         |
//+------------------------------------------------------------------+

void RefreshGlobalVars()
{
  valLowestMarginLevel = GlobalVariableGet(LowestMarginLevel);
  valLargestFloatingLoss = GlobalVariableGet(LargestFloatingLoss);
  valMaxFloatingDrawdown = GlobalVariableGet(MaxFloatingDrawdown);

  valLastFlatBal = GlobalVariableGet(LastFlatBal);
  valLastFlatEq  = GlobalVariableGet(LastFlatEq);

  valGBPUSDadded = GlobalVariableGet(GBPUSDadded);
  valEURGBPadded = GlobalVariableGet(EURGBPadded);
  valGBPJPYadded = GlobalVariableGet(GBPJPYadded);
  valUSDCHFadded = GlobalVariableGet(USDCHFadded);
  valNZDUSDadded = GlobalVariableGet(NZDUSDadded);
  valAUDJPYadded = GlobalVariableGet(AUDJPYadded);
  valEURJPYadded = GlobalVariableGet(EURJPYadded);

  valEURUSDadded = GlobalVariableGet(EURUSDadded);
  valUSDJPYadded = GlobalVariableGet(USDJPYadded);
  valAUDUSDadded = GlobalVariableGet(AUDUSDadded);
  valNZDJPYadded = GlobalVariableGet(NZDJPYadded);
  valGBPCHFadded = GlobalVariableGet(GBPCHFadded);
  valCHFJPYadded = GlobalVariableGet(CHFJPYadded);
  valEURCHFadded = GlobalVariableGet(EURCHFadded);

  return(0);
}

//+------------------------------------------------------------------+
//|  Get important account parameters that affect how the lot size   |
//|  will be set.                                                    |
//+------------------------------------------------------------------+

void GetAccountInfo()
{
  // Get account leverage, account type.
  Leverage       = AccountLeverage();

  AccountTypeVal = MarketInfo(Symbol(), MODE_LOTSIZE);
  MaxLots        = MarketInfo(Symbol(), MODE_MAXLOT);
  MinLots        = MarketInfo(Symbol(), MODE_MINLOT);

  return(0);
}

//+------------------------------------------------------------------+
//|                 Set the traded symbol strings.                   |
//+------------------------------------------------------------------+

void SetSymbols()
{
  string AddMangle = "";
  if (StringLen(Symbol()) > 6) AddMangle = StringSubstr(Symbol(), 6);

  GBPUSDsym = "GBPUSD" + AddMangle;
  EURGBPsym = "EURGBP" + AddMangle;
  GBPJPYsym = "GBPJPY" + AddMangle;
  USDCHFsym = "USDCHF" + AddMangle;
  NZDUSDsym = "NZDUSD" + AddMangle;
  AUDJPYsym = "AUDJPY" + AddMangle;
  EURJPYsym = "EURJPY" + AddMangle;

  EURUSDsym = "EURUSD" + AddMangle;
  USDJPYsym = "USDJPY" + AddMangle;
  AUDUSDsym = "AUDUSD" + AddMangle;
  NZDJPYsym = "NZDJPY" + AddMangle;
  GBPCHFsym = "GBPCHF" + AddMangle;
  CHFJPYsym = "CHFJPY" + AddMangle;
  EURCHFsym = "EURCHF" + AddMangle;

  SymbolArray[GBPUSDidx] = GBPUSDsym;
  SymbolArray[EURGBPidx] = EURGBPsym;
  SymbolArray[GBPJPYidx] = GBPJPYsym;
  SymbolArray[USDCHFidx] = USDCHFsym;
  SymbolArray[NZDUSDidx] = NZDUSDsym;
  SymbolArray[AUDJPYidx] = AUDJPYsym;
  SymbolArray[EURJPYidx] = EURJPYsym;

  SymbolArray[EURUSDidx] = EURUSDsym;
  SymbolArray[USDJPYidx] = USDJPYsym;
  SymbolArray[AUDUSDidx] = AUDUSDsym;
  SymbolArray[NZDJPYidx] = NZDJPYsym;
  SymbolArray[GBPCHFidx] = GBPCHFsym;
  SymbolArray[CHFJPYidx] = CHFJPYsym;
  SymbolArray[EURCHFidx] = EURCHFsym;

  return(0);
}

//+------------------------------------------------------------------+
//|                    Reset the phantom trades.                     |
//+------------------------------------------------------------------+

void ResetPhantoms()
{
  GBPUSDask = 0.0;
  EURGBPask = 0.0;
  GBPJPYask = 0.0;
  USDCHFask = 0.0;
  NZDUSDask = 0.0;
  AUDJPYask = 0.0;
  EURJPYask = 0.0;

  EURUSDbid = 0.0;
  USDJPYbid = 0.0;
  AUDUSDbid = 0.0;
  NZDJPYbid = 0.0;
  GBPCHFbid = 0.0;
  CHFJPYbid = 0.0;
  EURCHFbid = 0.0;

  GlobalVariableSet(strGBPUSDask, GBPUSDask);
  GlobalVariableSet(strEURGBPask, EURGBPask);
  GlobalVariableSet(strGBPJPYask, GBPJPYask);
  GlobalVariableSet(strUSDCHFask, USDCHFask);
  GlobalVariableSet(strNZDUSDask, NZDUSDask);
  GlobalVariableSet(strAUDJPYask, AUDJPYask);
  GlobalVariableSet(strEURJPYask, EURJPYask);

  GlobalVariableSet(strEURUSDbid, EURUSDbid);
  GlobalVariableSet(strUSDJPYbid, USDJPYbid);
  GlobalVariableSet(strAUDUSDbid, AUDUSDbid);
  GlobalVariableSet(strNZDJPYbid, NZDJPYbid);
  GlobalVariableSet(strGBPCHFbid, GBPCHFbid);
  GlobalVariableSet(strCHFJPYbid, CHFJPYbid);
  GlobalVariableSet(strEURCHFbid, EURCHFbid);

  return(0);
}

//+------------------------------------------------------------------+
//|                       Open phantom trades.                       |
//+------------------------------------------------------------------+

void OpenPhantomTrades()
{
  if (GBPUSDask == 0.0 && EURGBPask == 0.0 &&
      GBPJPYask == 0.0 && USDCHFask == 0.0 &&
      NZDUSDask == 0.0 && AUDJPYask == 0.0 &&
      EURJPYask == 0.0 &&
      
      EURUSDbid == 0.0 && USDJPYbid == 0.0 &&
      AUDUSDbid == 0.0 && NZDJPYbid == 0.0 &&
      GBPCHFbid == 0.0 && CHFJPYbid == 0.0 &&
      EURCHFbid == 0.0)
  {
    GBPUSDask = MarketInfo(GBPUSDsym, MODE_ASK);
    EURGBPask = MarketInfo(EURGBPsym, MODE_ASK);
    GBPJPYask = MarketInfo(GBPJPYsym, MODE_ASK);
    USDCHFask = MarketInfo(USDCHFsym, MODE_ASK);
    NZDUSDask = MarketInfo(NZDUSDsym, MODE_ASK);
    AUDJPYask = MarketInfo(AUDJPYsym, MODE_ASK);
    EURJPYask = MarketInfo(EURJPYsym, MODE_ASK);

    EURUSDbid = MarketInfo(EURUSDsym, MODE_BID);
    USDJPYbid = MarketInfo(USDJPYsym, MODE_BID);
    AUDUSDbid = MarketInfo(AUDUSDsym, MODE_BID);
    NZDJPYbid = MarketInfo(NZDJPYsym, MODE_BID);
    GBPCHFbid = MarketInfo(GBPCHFsym, MODE_BID);
    CHFJPYbid = MarketInfo(CHFJPYsym, MODE_BID);
    EURCHFbid = MarketInfo(EURCHFsym, MODE_BID);

    GlobalVariableSet(strGBPUSDask, GBPUSDask);
    GlobalVariableSet(strEURGBPask, EURGBPask);
    GlobalVariableSet(strGBPJPYask, GBPJPYask);
    GlobalVariableSet(strUSDCHFask, USDCHFask);
    GlobalVariableSet(strNZDUSDask, NZDUSDask);
    GlobalVariableSet(strAUDJPYask, AUDJPYask);
    GlobalVariableSet(strEURJPYask, EURJPYask);

    GlobalVariableSet(strEURUSDbid, EURUSDbid);
    GlobalVariableSet(strUSDJPYbid, USDJPYbid);
    GlobalVariableSet(strAUDUSDbid, AUDUSDbid);
    GlobalVariableSet(strNZDJPYbid, NZDJPYbid);
    GlobalVariableSet(strGBPCHFbid, GBPCHFbid);
    GlobalVariableSet(strCHFJPYbid, CHFJPYbid);
    GlobalVariableSet(strEURCHFbid, EURCHFbid);
  }

  return(0);
}

//+------------------------------------------------------------------+
//|             Set the account type and minimum equity.             |
//+------------------------------------------------------------------+

void SetAccountType()
{
  if (AccountTypeVal == MiniSize || StringLen(Symbol()) == 7)
  {
    AccountIsMini     = true;
    AccountTypeString = "MINI";
  }
  else if (AccountTypeVal == StdSize || StringLen(Symbol()) == 6)
  {
    AccountIsMini     = false;
    AccountTypeString = "STANDARD";
  }
  
  return(0);
}

//+------------------------------------------------------------------+
//|                 Set the lot size for any trades.                 |
//+------------------------------------------------------------------+

void SetLotSize()
{
  Investment = MaxMarginToUse / 100.0;

  // The symbol the EA is attached to should be good enough for the purposes of LOTSIZE
  UseLots = valLastFlatEq * Investment * (Leverage / MarketInfo(Symbol(), MODE_LOTSIZE));
  UseLots = StrToDouble(DoubleToStr(UseLots,2));

  if (UseSmallestLot || UseLots < MinLots) UseLots = MinLots;
  if (UseLots > MaxLots) UseLots = MaxLots;

  return(0);
}

//+------------------------------------------------------------------+
//|  Do some accounting -- count the profit/loss, the open trades,   |
//|  and the number of open lots.                                    |
//+------------------------------------------------------------------+

void Count_PL_Trades_Lots()
{
  NumBuys            =    0;
  NumSells           =    0;
  TotalTrades        =    0;
  EAPL               =    0.0;
  BuyPL              =    0.0;
  SellPL             =    0.0;
  TotalLots          =    0.0;
  BuyLots            =    0.0;
  SellLots           =    0.0;

  GBPUSDbuys = 0; GBPUSDsells = 0;
  EURGBPbuys = 0; EURGBPsells = 0;
  GBPJPYbuys = 0; GBPJPYsells = 0;
  USDCHFbuys = 0; USDCHFsells = 0;
  NZDUSDbuys = 0; NZDUSDsells = 0;
  AUDJPYbuys = 0; AUDJPYsells = 0;
  EURJPYbuys = 0; EURJPYsells = 0;

  EURUSDbuys = 0; EURUSDsells = 0;
  USDJPYbuys = 0; USDJPYsells = 0;
  AUDUSDbuys = 0; AUDUSDsells = 0;
  NZDJPYbuys = 0; NZDJPYsells = 0;
  GBPCHFbuys = 0; GBPCHFsells = 0;
  CHFJPYbuys = 0; CHFJPYsells = 0;
  EURCHFbuys = 0; EURCHFsells = 0;

  BiggestWinnerPL = 0.0;
  BiggestWinnerLots = 0.0;
  BiggestWinnerTicket = 0;
  BiggestWinnerType = "";
  BiggestWinnerSymbol = "";

  BiggestLoserPL = 0.0;
  BiggestLoserLots = 0.0;
  BiggestLoserTicket = 0;
  BiggestLoserType = "";
  BiggestLoserSymbol = "";

  for (i = 0; i < OrdersTotal(); i++)
  {
    OrderSelect(i,SELECT_BY_POS,MODE_TRADES);

    if (OrderMagicNumber() == MagicNumber)
    {
      PairOverallPL = OrderProfit() + OrderSwap() + OrderCommission();
      EAPL  += PairOverallPL;
      TotalLots += OrderLots();

      if (OrderType() == OP_BUY)
      {
        BuyPL += PairOverallPL;

        if (PairOverallPL > BiggestWinnerPL)
        {
          BiggestWinnerPL     = PairOverallPL;
          BiggestWinnerLots   = OrderLots();
          BiggestWinnerTicket = OrderTicket();
          BiggestWinnerType   = "BUY";
          BiggestWinnerSymbol = OrderSymbol();
        }

        if (PairOverallPL < BiggestLoserPL)
        {
          BiggestLoserPL     = PairOverallPL;
          BiggestLoserLots   = OrderLots();
          BiggestLoserTicket = OrderTicket();
          BiggestLoserType   = "BUY";
          BiggestLoserSymbol = OrderSymbol();
        }

        BuyLots += OrderLots();

        NumBuys++;

        if (OrderSymbol() == GBPUSDsym) { GBPUSDbuys++; GBPUSDPL = PairOverallPL; }
        else
        if (OrderSymbol() == EURGBPsym) { EURGBPbuys++; EURGBPPL = PairOverallPL; }
        else
        if (OrderSymbol() == GBPJPYsym) { GBPJPYbuys++; GBPJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == USDCHFsym) { USDCHFbuys++; USDCHFPL = PairOverallPL; }
        else
        if (OrderSymbol() == NZDUSDsym) { NZDUSDbuys++; NZDUSDPL = PairOverallPL; }
        else
        if (OrderSymbol() == AUDJPYsym) { AUDJPYbuys++; AUDJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == EURJPYsym) { EURJPYbuys++; EURJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == EURUSDsym) { EURUSDbuys++; EURUSDPL = PairOverallPL; }
        else
        if (OrderSymbol() == USDJPYsym) { USDJPYbuys++; USDJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == AUDUSDsym) { AUDUSDbuys++; AUDUSDPL = PairOverallPL; }
        else
        if (OrderSymbol() == NZDJPYsym) { NZDJPYbuys++; NZDJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == GBPCHFsym) { GBPCHFbuys++; GBPCHFPL = PairOverallPL; }
        else
        if (OrderSymbol() == CHFJPYsym) { CHFJPYbuys++; CHFJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == EURCHFsym) { EURCHFbuys++; EURCHFPL = PairOverallPL; }
      }

      if (OrderType() == OP_SELL)
      {
        SellPL += PairOverallPL;

        if (PairOverallPL> BiggestWinnerPL)
        {
          BiggestWinnerPL     = PairOverallPL;
          BiggestWinnerLots   = OrderLots();
          BiggestWinnerTicket = OrderTicket();
          BiggestWinnerType   = "SELL";
          BiggestWinnerSymbol = OrderSymbol();
        }

        if (PairOverallPL< BiggestLoserPL)
        {
          BiggestLoserPL     = PairOverallPL;
          BiggestLoserLots   = OrderLots();
          BiggestLoserTicket = OrderTicket();
          BiggestLoserType   = "SELL";
          BiggestLoserSymbol = OrderSymbol();
        }

        SellLots += OrderLots();

        NumSells++;

        if (OrderSymbol() == GBPUSDsym) { GBPUSDsells++; GBPUSDPL = PairOverallPL; }
        else
        if (OrderSymbol() == EURGBPsym) { EURGBPsells++; EURGBPPL = PairOverallPL; }
        else
        if (OrderSymbol() == GBPJPYsym) { GBPJPYsells++; GBPJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == USDCHFsym) { USDCHFsells++; USDCHFPL = PairOverallPL; }
        else
        if (OrderSymbol() == NZDUSDsym) { NZDUSDsells++; NZDUSDPL = PairOverallPL; }
        else
        if (OrderSymbol() == AUDJPYsym) { AUDJPYsells++; AUDJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == EURJPYsym) { EURJPYsells++; EURJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == EURUSDsym) { EURUSDsells++; EURUSDPL = PairOverallPL; }
        else
        if (OrderSymbol() == USDJPYsym) { USDJPYsells++; USDJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == AUDUSDsym) { AUDUSDsells++; AUDUSDPL = PairOverallPL; }
        else
        if (OrderSymbol() == NZDJPYsym) { NZDJPYsells++; NZDJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == GBPCHFsym) { GBPCHFsells++; GBPCHFPL = PairOverallPL; }
        else
        if (OrderSymbol() == CHFJPYsym) { CHFJPYsells++; CHFJPYPL = PairOverallPL; }
        else
        if (OrderSymbol() == EURCHFsym) { EURCHFsells++; EURCHFPL = PairOverallPL; }
      }
    }
  }
  TotalTrades = NumBuys+NumSells;

  return(0);
}

//+------------------------------------------------------------------+
//|         Set the dollar profit and trim target values.            |
//+------------------------------------------------------------------+

void SetExitTargets()
{
  DollarProfitTarget = StrToDouble(DoubleToStr(valLastFlatEq*ProfitPct/100.0,2));

  if (AccountIsMini)
  {
    if (DollarProfitTarget > MaxMiniProfit) DollarProfitTarget = MaxMiniProfit;
  }
  else
  {
    if (DollarProfitTarget > MaxStdProfit) DollarProfitTarget = MaxStdProfit;
  }

  return(0);
}

//+------------------------------------------------------------------+
//|                 Close all of the open trades.                    |
//+------------------------------------------------------------------+

void CloseAllTradesIfNeeded()
{
  if (BidsHaveChanged && CloseAll)
  {
    for(i = 0; i < OrdersTotal(); i++)
    {
      OrderSelect(i,SELECT_BY_POS,MODE_TRADES);

      if (OrderMagicNumber() == MagicNumber)
      {
        if (OrderType() == OP_BUY)
        {
          Comment("In full closure mode.  Closing a ", OrderSymbol(), " buy trade...");
          Print("In full closure mode.  Closing a ", OrderSymbol(), " buy trade...");
          OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(), MODE_BID),Slippage,White);
          Sleep(1000);
        }    
        else
        if (OrderType() == OP_SELL)
        {
          Comment("In full closure mode.  Closing a ", OrderSymbol(), " sell trade...");
          Print("In full closure mode.  Closing a ", OrderSymbol(), " sell trade...");
          OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(), MODE_ASK),Slippage,White);
          Sleep(1000);
        }
      }
    }
  }
  
  return(0);
}

//+------------------------------------------------------------------+
//|                 Clear all symbol-added marks.                    |
//+------------------------------------------------------------------+

void ClearSymbolMarks()
{
  valGBPUSDadded = false;
  GlobalVariableSet(GBPUSDadded, valGBPUSDadded);

  valEURGBPadded = false;
  GlobalVariableSet(EURGBPadded, valEURGBPadded);

  valGBPJPYadded = false;
  GlobalVariableSet(GBPJPYadded, valGBPJPYadded);

  valUSDCHFadded = false;
  GlobalVariableSet(USDCHFadded, valUSDCHFadded);

  valNZDUSDadded = false;
  GlobalVariableSet(NZDUSDadded, valNZDUSDadded);

  valAUDJPYadded = false;
  GlobalVariableSet(AUDJPYadded, valAUDJPYadded);

  valEURJPYadded = false;
  GlobalVariableSet(EURJPYadded, valEURJPYadded);

  valEURUSDadded = false;
  GlobalVariableSet(EURUSDadded, valEURUSDadded);

  valUSDJPYadded = false;
  GlobalVariableSet(USDJPYadded, valUSDJPYadded);

  valAUDUSDadded = false;
  GlobalVariableSet(AUDUSDadded, valAUDUSDadded);

  valNZDJPYadded = false;
  GlobalVariableSet(NZDJPYadded, valNZDJPYadded);

  valGBPCHFadded = false;
  GlobalVariableSet(GBPCHFadded, valGBPCHFadded);

  valCHFJPYadded = false;
  GlobalVariableSet(CHFJPYadded, valCHFJPYadded);

  valEURCHFadded = false;
  GlobalVariableSet(EURCHFadded, valEURCHFadded);

  return(0);
}

//+------------------------------------------------------------------+
//|                 Mark the given currency pair as added.           |
//+------------------------------------------------------------------+

void MarkSymbolAdded(string theSymbol)
{
  if (theSymbol == GBPUSDsym)
  {
    valGBPUSDadded = true;
    GlobalVariableSet(GBPUSDadded, valGBPUSDadded);
  }
  else
  if (theSymbol == EURGBPsym)
  {
    valEURGBPadded = true;
    GlobalVariableSet(EURGBPadded, valEURGBPadded);
  }
  else
  if (theSymbol == GBPJPYsym)
  {
    valGBPJPYadded = true;
    GlobalVariableSet(GBPJPYadded, valGBPJPYadded);
  }
  else
  if (theSymbol == USDCHFsym)
  {
    valUSDCHFadded = true;
    GlobalVariableSet(USDCHFadded, valUSDCHFadded);
  }
  else
  if (theSymbol == NZDUSDsym)
  {
    valNZDUSDadded = true;
    GlobalVariableSet(NZDUSDadded, valNZDUSDadded);
  }
  else
  if (theSymbol == AUDJPYsym)
  {
    valAUDJPYadded = true;
    GlobalVariableSet(AUDJPYadded, valAUDJPYadded);
  }
  else
  if (theSymbol == EURJPYsym)
  {
    valEURJPYadded = true;
    GlobalVariableSet(EURJPYadded, valEURJPYadded);
  }
  else
  if (theSymbol == EURUSDsym)
  {
    valEURUSDadded = true;
    GlobalVariableSet(EURUSDadded, valEURUSDadded);
  }
  else
  if (theSymbol == USDJPYsym)
  {
    valUSDJPYadded = true;
    GlobalVariableSet(USDJPYadded, valUSDJPYadded);
  }
  else
  if (theSymbol == AUDUSDsym)
  {
    valAUDUSDadded = true;
    GlobalVariableSet(AUDUSDadded, valAUDUSDadded);
  }
  else
  if (theSymbol == NZDJPYsym)
  {
    valNZDJPYadded = true;
    GlobalVariableSet(NZDJPYadded, valNZDJPYadded);
  }
  else
  if (theSymbol == GBPCHFsym)
  {
    valGBPCHFadded = true;
    GlobalVariableSet(GBPCHFadded, valGBPCHFadded);
  }
  else
  if (theSymbol == CHFJPYsym)
  {
    valCHFJPYadded = true;
    GlobalVariableSet(CHFJPYadded, valCHFJPYadded);
  }
  else
  if (theSymbol == EURCHFsym)
  {
    valEURCHFadded = true;
    GlobalVariableSet(EURCHFadded, valEURCHFadded);
  }

  return(0);
}

//+------------------------------------------------------------------+
//|          Check if the given currency is marked as added.         |
//+------------------------------------------------------------------+

bool SymbolMarked(string theSymbol)
{
  if (theSymbol == GBPUSDsym && valGBPUSDadded)
  {
    return(true);
  }
  else
  if (theSymbol == EURGBPsym && valEURGBPadded)
  {
    return(true);
  }
  else
  if (theSymbol == GBPJPYsym && valGBPJPYadded)
  {
    return(true);
  }
  else
  if (theSymbol == USDCHFsym && valUSDCHFadded)
  {
    return(true);
  }
  else
  if (theSymbol == NZDUSDsym && valNZDUSDadded)
  {
    return(true);
  }
  else
  if (theSymbol == AUDJPYsym && valAUDJPYadded)
  {
    return(true);
  }
  else
  if (theSymbol == EURJPYsym && valEURJPYadded)
  {
    return(true);
  }
  else
  if (theSymbol == EURUSDsym && valEURUSDadded)
  {
    return(true);
  }
  else
  if (theSymbol == USDJPYsym && valUSDJPYadded)
  {
    return(true);
  }
  else
  if (theSymbol == AUDUSDsym && valAUDUSDadded)
  {
    return(true);
  }
  else
  if (theSymbol == NZDJPYsym && valNZDJPYadded)
  {
    return(true);
  }
  else
  if (theSymbol == GBPCHFsym && valGBPCHFadded)
  {
    return(true);
  }
  else
  if (theSymbol == CHFJPYsym && valCHFJPYadded)
  {
    return(true);
  }
  else
  if (theSymbol == EURCHFsym && valEURCHFadded)
  {
    return(true);
  }

  return(false);
}

//+------------------------------------------------------------------+
//|     Correct problem of brokers using 3 or 5 digit pricing        |
//+------------------------------------------------------------------+

double SetPoint(string theSymbol)
{
  double mPoint, mDigits;
   
  mDigits = MarketInfo(theSymbol, MODE_DIGITS);

  if (mDigits < 4)
    mPoint = 0.01;
  else
    mPoint = 0.0001;

  return(mPoint);
}

//+------------------------------------------------------------------+
//|     Correct problem of brokers using 3 or 5 digit pricing        |
//+------------------------------------------------------------------+

double SetTickValue(string theSymbol, double thePoint)
{
  double mTickValue;
   
  if (thePoint/10.0 == MarketInfo(theSymbol, MODE_POINT))
  {
    mTickValue = MarketInfo(theSymbol, MODE_TICKVALUE)*10.0;
  }
  else // if (thePoint == MarketInfo(theSymbol, MODE_POINT))
  {
    mTickValue = MarketInfo(theSymbol, MODE_TICKVALUE);
  }

  return(mTickValue);
}

//+------------------------------------------------------------------+
//|                Set the value of Point for each pair.             |
//+------------------------------------------------------------------+

void SetPointsAndTickvalues()
{
  GBPUSDpoint = SetPoint(GBPUSDsym);
  EURGBPpoint = SetPoint(EURGBPsym);
  GBPJPYpoint = SetPoint(GBPJPYsym);
  USDCHFpoint = SetPoint(USDCHFsym);
  NZDUSDpoint = SetPoint(NZDUSDsym);
  AUDJPYpoint = SetPoint(AUDJPYsym);
  EURJPYpoint = SetPoint(EURJPYsym);

  EURUSDpoint = SetPoint(EURUSDsym);
  USDJPYpoint = SetPoint(USDJPYsym);
  AUDUSDpoint = SetPoint(AUDUSDsym);
  NZDJPYpoint = SetPoint(NZDJPYsym);
  GBPCHFpoint = SetPoint(GBPCHFsym);
  CHFJPYpoint = SetPoint(CHFJPYsym);
  EURCHFpoint = SetPoint(EURCHFsym);

  GBPUSDtickval = SetTickValue(GBPUSDsym, GBPUSDpoint);
  TickvalArray[GBPUSDidx] = GBPUSDtickval;

  EURGBPtickval = SetTickValue(EURGBPsym, EURGBPpoint);
  TickvalArray[EURGBPidx] = EURGBPtickval;

  GBPJPYtickval = SetTickValue(GBPJPYsym, GBPJPYpoint);
  TickvalArray[GBPJPYidx] = GBPJPYtickval;

  USDCHFtickval = SetTickValue(USDCHFsym, USDCHFpoint);
  TickvalArray[USDCHFidx] = USDCHFtickval;

  NZDUSDtickval = SetTickValue(NZDUSDsym, NZDUSDpoint);
  TickvalArray[NZDUSDidx] = NZDUSDtickval;

  AUDJPYtickval = SetTickValue(AUDJPYsym, AUDJPYpoint);
  TickvalArray[AUDJPYidx] = AUDJPYtickval;

  EURJPYtickval = SetTickValue(EURJPYsym, EURJPYpoint);
  TickvalArray[EURJPYidx] = EURJPYtickval;

  EURUSDtickval = SetTickValue(EURUSDsym, EURUSDpoint);
  TickvalArray[EURUSDidx] = EURUSDtickval;

  USDJPYtickval = SetTickValue(USDJPYsym, USDJPYpoint);
  TickvalArray[USDJPYidx] = USDJPYtickval;

  AUDUSDtickval = SetTickValue(AUDUSDsym, AUDUSDpoint);
  TickvalArray[AUDUSDidx] = AUDUSDtickval;

  NZDJPYtickval = SetTickValue(NZDJPYsym, NZDJPYpoint);
  TickvalArray[NZDJPYidx] = NZDJPYtickval;

  GBPCHFtickval = SetTickValue(GBPCHFsym, GBPCHFpoint);
  TickvalArray[GBPCHFidx] = GBPCHFtickval;

  CHFJPYtickval = SetTickValue(CHFJPYsym, CHFJPYpoint);
  TickvalArray[CHFJPYidx] = CHFJPYtickval;

  EURCHFtickval = SetTickValue(EURCHFsym, EURCHFpoint);
  TickvalArray[EURCHFidx] = EURCHFtickval;

  return(0);
}

//+------------------------------------------------------------------+
//|                 Calculate PL for phantom trades.                 |
//+------------------------------------------------------------------+

void CalcPhantomPL()
{
  SetPointsAndTickvalues();
  
  if (GBPUSDpoint != 0.0)
  {
    GBPUSD_PL = (MarketInfo(GBPUSDsym, MODE_BID) - GBPUSDask) / GBPUSDpoint;
    GBPUSD_PL *= TickvalArray[GBPUSDidx]*UseLots;
    PL_Array[GBPUSDidx] = GBPUSD_PL;
  }

  if (EURGBPpoint != 0.0)
  {
    EURGBP_PL = (MarketInfo(EURGBPsym, MODE_BID) - EURGBPask) / EURGBPpoint;
    EURGBP_PL *= TickvalArray[EURGBPidx]*UseLots;
    PL_Array[EURGBPidx] = EURGBP_PL;
  }
  
  if (GBPJPYpoint != 0.0)
  {
    GBPJPY_PL = (MarketInfo(GBPJPYsym, MODE_BID) - GBPJPYask) / GBPJPYpoint;
    GBPJPY_PL *= TickvalArray[GBPJPYidx]*UseLots;
    PL_Array[GBPJPYidx] = GBPJPY_PL;
  }

  if (USDCHFpoint != 0.0)
  {
    USDCHF_PL = (MarketInfo(USDCHFsym, MODE_BID) - USDCHFask) / USDCHFpoint;
    USDCHF_PL *= TickvalArray[USDCHFidx]*UseLots;
    PL_Array[USDCHFidx] = USDCHF_PL;
  }

  if (NZDUSDpoint != 0.0)
  {
    NZDUSD_PL = (MarketInfo(NZDUSDsym, MODE_BID) - NZDUSDask) / NZDUSDpoint;
    NZDUSD_PL *= TickvalArray[NZDUSDidx]*UseLots;
    PL_Array[NZDUSDidx] = NZDUSD_PL;
  }

  if (AUDJPYpoint != 0.0)
  {
    AUDJPY_PL = (MarketInfo(AUDJPYsym, MODE_BID) - AUDJPYask) / AUDJPYpoint;
    AUDJPY_PL *= TickvalArray[AUDJPYidx]*UseLots;
    PL_Array[AUDJPYidx] = AUDJPY_PL;
  }

  if (EURJPYpoint != 0.0)
  {
    EURJPY_PL = (MarketInfo(EURJPYsym, MODE_BID) - EURJPYask) / EURJPYpoint;
    EURJPY_PL *= TickvalArray[EURJPYidx]*UseLots;
    PL_Array[EURJPYidx] = EURJPY_PL;
  }

  phantomBuyPL = GBPUSD_PL + EURGBP_PL + GBPJPY_PL + USDCHF_PL + NZDUSD_PL + AUDJPY_PL + EURJPY_PL;

  if (EURUSDpoint != 0.0)
  {
    EURUSD_PL = (EURUSDbid - MarketInfo(EURUSDsym, MODE_ASK)) / EURUSDpoint;
    EURUSD_PL *= TickvalArray[EURUSDidx]*UseLots;
    PL_Array[EURUSDidx] = EURUSD_PL;
  }

  if (USDJPYpoint != 0.0)
  {
    USDJPY_PL = (USDJPYbid - MarketInfo(USDJPYsym, MODE_ASK)) / USDJPYpoint;
    USDJPY_PL *= TickvalArray[USDJPYidx]*UseLots;
    PL_Array[USDJPYidx] = USDJPY_PL;
  }

  if (AUDUSDpoint != 0.0)
  {
    AUDUSD_PL = (AUDUSDbid - MarketInfo(AUDUSDsym, MODE_ASK)) / AUDUSDpoint;
    AUDUSD_PL *= TickvalArray[AUDUSDidx]*UseLots;
    PL_Array[AUDUSDidx] = AUDUSD_PL;
  }

  if (NZDJPYpoint != 0.0)
  {
    NZDJPY_PL = (NZDJPYbid - MarketInfo(NZDJPYsym, MODE_ASK)) / NZDJPYpoint;
    NZDJPY_PL *= TickvalArray[NZDJPYidx]*UseLots;
    PL_Array[NZDJPYidx] = NZDJPY_PL;
  }

  if (GBPCHFpoint != 0.0)
  {
    GBPCHF_PL = (GBPCHFbid - MarketInfo(GBPCHFsym, MODE_ASK)) / GBPCHFpoint;
    GBPCHF_PL *= TickvalArray[GBPCHFidx]*UseLots;
    PL_Array[GBPCHFidx] = GBPCHF_PL;
  }

  if (CHFJPYpoint != 0.0)
  {
    CHFJPY_PL = (CHFJPYbid - MarketInfo(CHFJPYsym, MODE_ASK)) / CHFJPYpoint;
    CHFJPY_PL *= TickvalArray[CHFJPYidx]*UseLots;
    PL_Array[CHFJPYidx] = CHFJPY_PL;
  }

  if (EURCHFpoint != 0.0)
  {
    EURCHF_PL = (EURCHFbid - MarketInfo(EURCHFsym, MODE_ASK)) / EURCHFpoint;
    EURCHF_PL *= TickvalArray[EURCHFidx]*UseLots;
    PL_Array[EURCHFidx] = EURCHF_PL;
  }

  phantomSellPL = EURUSD_PL + USDJPY_PL + AUDUSD_PL + NZDJPY_PL + GBPCHF_PL + CHFJPY_PL + EURCHF_PL;
  phantomEAPL = phantomBuyPL + phantomSellPL;

  // Determine biggest phantom winner.

  BiggestPhantomWinnerPL = 0.0;
  BiggestPhantomWinnerType = "";
  BiggestPhantomWinnerSymbol = "";

  if (GBPUSD_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = GBPUSD_PL;
    BiggestPhantomWinnerType   = "BUY";
    BiggestPhantomWinnerSymbol = GBPUSDsym;
  }

  if (EURGBP_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = EURGBP_PL;
    BiggestPhantomWinnerType   = "BUY";
    BiggestPhantomWinnerSymbol = EURGBPsym;
  }
  if (GBPJPY_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = GBPJPY_PL;
    BiggestPhantomWinnerType   = "BUY";
    BiggestPhantomWinnerSymbol = GBPJPYsym;
  }
  if (USDCHF_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = USDCHF_PL;
    BiggestPhantomWinnerType   = "BUY";
    BiggestPhantomWinnerSymbol = USDCHFsym;
  }
  if (NZDUSD_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = NZDUSD_PL;
    BiggestPhantomWinnerType   = "BUY";
    BiggestPhantomWinnerSymbol = NZDUSDsym;
  }
  if (AUDJPY_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = AUDJPY_PL;
    BiggestPhantomWinnerType   = "BUY";
    BiggestPhantomWinnerSymbol = AUDJPYsym;
  }
  if (EURJPY_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = EURJPY_PL;
    BiggestPhantomWinnerType   = "BUY";
    BiggestPhantomWinnerSymbol = EURJPYsym;
  }


  if (EURUSD_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = EURUSD_PL;
    BiggestPhantomWinnerType   = "SELL";
    BiggestPhantomWinnerSymbol = EURUSDsym;
  }
  if (USDJPY_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = USDJPY_PL;
    BiggestPhantomWinnerType   = "SELL";
    BiggestPhantomWinnerSymbol = USDJPYsym;
  }
  if (AUDUSD_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = AUDUSD_PL;
    BiggestPhantomWinnerType   = "SELL";
    BiggestPhantomWinnerSymbol = AUDUSDsym;
  }
  if (NZDJPY_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = NZDJPY_PL;
    BiggestPhantomWinnerType   = "SELL";
    BiggestPhantomWinnerSymbol = NZDJPYsym;
  }
  if (GBPCHF_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = GBPCHF_PL;
    BiggestPhantomWinnerType   = "SELL";
    BiggestPhantomWinnerSymbol = GBPCHFsym;
  }
  if (CHFJPY_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = CHFJPY_PL;
    BiggestPhantomWinnerType   = "SELL";
    BiggestPhantomWinnerSymbol = CHFJPYsym;
  }
  if (EURCHF_PL > BiggestPhantomWinnerPL)
  {
    BiggestPhantomWinnerPL     = EURCHF_PL;
    BiggestPhantomWinnerType   = "SELL";
    BiggestPhantomWinnerSymbol = EURCHFsym;
  }

  return(0);
}

//+------------------------------------------------------------------+
//|               Check if all symbol trades in profit.              |
//+------------------------------------------------------------------+

bool AllSymbolTradesInProfit(string theSymbol)
{
  for (j = 0; j < OrdersTotal(); j++)
  {
    OrderSelect(j,SELECT_BY_POS,MODE_TRADES);

    if (OrderMagicNumber() == MagicNumber &&
        OrderSymbol() == theSymbol        &&
        OrderProfit() <= 0.0)
    {
      return(false);
    }
  }

  return(true);
}

//+------------------------------------------------------------------+
//|                     Add to winning trades.                       |
//+------------------------------------------------------------------+

void AddIfNeeded()
{
  if (TimeMinute(TimeCurrent()) != 15 && TimeMinute(TimeCurrent()) != 45) ClearSymbolMarks();

  if ((BidsHaveChanged &&
      (TimeMinute(TimeCurrent()) == 15 || TimeMinute(TimeCurrent()) == 45) &&
     !CloseAll))
  {
    for (i = GBPUSDidx; i <= EURCHFidx; i++)
    {
      if (PL_Array[i] > 0.0 &&
           (SymbolArray[i] == EURJPYsym || SymbolArray[i] == EURUSDsym || SymbolArray[i] == USDJPYsym) &&
         !SymbolMarked(SymbolArray[i]))
      {
        if (AllSymbolTradesInProfit(SymbolArray[i]) &&
            !SymbolMarked(SymbolArray[i]) )
        {
          if (i < 7 )
          {
            if (GetQQE(SymbolArray[i], QQE_TrendTimeframe) == 0 && GetQQE(SymbolArray[i], QQE_EntryTimeframe) == 0) {             // we do not trade if qqe doesn't match
               Comment("Adding a " + SymbolArray[i] + " buy trade...");
               Print("Adding a " + SymbolArray[i] + " long. QQE Trend is: ", GetQQE(SymbolArray[i], QQE_TrendTimeframe), ", QQE Entry is: ", GetQQE(SymbolArray[i], QQE_EntryTimeframe), " (0=long, 1=short)");
               OrderSendResult = OrderSend(SymbolArray[i],OP_BUY,UseLots,MarketInfo(SymbolArray[i], MODE_ASK),
                                         Slippage,0,0,"Adding to a long phantom winner",MagicNumber,Blue);
               if (OrderSendResult > 0) MarkSymbolAdded(SymbolArray[i]);
               Sleep(1000);
            }
          }
          else
          // if (i >= 7)
          {
            if (GetQQE(SymbolArray[i], QQE_TrendTimeframe) == 1 && GetQQE(SymbolArray[i], QQE_EntryTimeframe) == 1) {               // same for shorts, don't trade against qqe trend!
               Comment("Adding a " + SymbolArray[i] + " sell trade...");
               Print("Adding a " + SymbolArray[i] + " short. QQE Trend is: ", GetQQE(SymbolArray[i], QQE_TrendTimeframe), ", QQE Entry is: ", GetQQE(SymbolArray[i], QQE_EntryTimeframe), " (0=long, 1=short)");
               OrderSendResult = OrderSend(SymbolArray[i],OP_SELL,UseLots,MarketInfo(SymbolArray[i], MODE_BID),
                                           Slippage,0,0,"Adding to a short phantom winner",MagicNumber,Red);
               if (OrderSendResult > 0) MarkSymbolAdded(SymbolArray[i]);
               Sleep(1000);
            }
          }
        }      
      } 
    } 
  }

  return(0);
}

//+------------------------------------------------------------------+
//|   Keep track of lowest margin level and largest floating loss.   |
//+------------------------------------------------------------------+

void ExamineMarginAndFloat()
{
  if (AccountMargin() > 0.0)
  {
    PercentMarginLevel = StrToDouble(DoubleToStr(100 * AccountEquity() / AccountMargin(), 2));

    if (PercentMarginLevel < valLowestMarginLevel)
    {
      valLowestMarginLevel = PercentMarginLevel;
      GlobalVariableSet(LowestMarginLevel, valLowestMarginLevel);
    }
  }

  if (EAPL < valLargestFloatingLoss)
  {
    valLargestFloatingLoss = StrToDouble(DoubleToStr(EAPL, 2));
    GlobalVariableSet(LargestFloatingLoss, valLargestFloatingLoss);
  }

  if ((valLargestFloatingLoss / valLastFlatEq) * 100.0 < valMaxFloatingDrawdown)
  {
    valMaxFloatingDrawdown = StrToDouble(DoubleToStr((valLargestFloatingLoss / valLastFlatEq) * 100.0, 2));
    GlobalVariableSet(MaxFloatingDrawdown, valMaxFloatingDrawdown);
  }

  return(0);
}

//+------------------------------------------------------------------+
//|                      Print Info to Chart                         |
//+------------------------------------------------------------------+

void PrintChartComments()
{
  CommentString = 
        "STRATEGY: Every 30 min, at 15 and 45, add a trade to every winning EURJPY, EURUSD, USDJPY phantom," +
        "\nbut only if all previous trades are winners. Close all when current equity exceeds ProfitPct above last flat equity." +
        "\n\nSignals are filtered using QQE Advance with parameters ("+QQE_SF+"/"+QQE_RSI_Period+"/"+QQE_WP+"), Trend TF="+TF(QQE_TrendTimeframe)+ " | Entry TF="+TF(QQE_EntryTimeframe)  + 
        "\n\nAccount Type: " + AccountTypeString + " Account,   Leverage: " + DoubleToStr(Leverage,0) + ":1" +
        ",   Margin %: " + DoubleToStr(PercentMarginLevel,2) + "%,   Lowest Margin %: " + DoubleToStr(valLowestMarginLevel,2) + "%" +
        "\nLargest Floating Loss: $" + DoubleToStr(valLargestFloatingLoss,2) + ",  Max Floating Drawdown %: " + DoubleToStr(valMaxFloatingDrawdown,2) + "%" +
        "\nBalance: $" + DoubleToStr(AccountBalance(),2) + ",   Equity: $" + DoubleToStr(AccountEquity(),2) +
        "\nLast Flat Balance: $" + DoubleToStr(valLastFlatBal,2) + ",   Last Flat Equity: $" + DoubleToStr(valLastFlatEq,2) +
        "\nDollar Profit Target: $" + DoubleToStr(DollarProfitTarget,2) + ",   Equity Profit Target: $" + DoubleToStr(valLastFlatEq+DollarProfitTarget,2) +
        "\nOpen Buys: " + DoubleToStr(NumBuys,0) + ",   Open Sells: " + DoubleToStr(NumSells,0) + ",   Total Open Trades: " + DoubleToStr(TotalTrades,0) +
        "\nGBPUSD Phantom PL: $" + DoubleToStr(GBPUSD_PL,2) + " (" + trend[GetQQE("GBPUSD", QQE_TrendTimeframe)] +")"+
        "\nEURGBP Phantom PL: $" + DoubleToStr(EURGBP_PL,2) + " (" + trend[GetQQE("EURGBP", QQE_TrendTimeframe)] +")"+
        "\nGBPJPY Phantom PL: $" + DoubleToStr(GBPJPY_PL,2) + " (" + trend[GetQQE("GBPJPY", QQE_TrendTimeframe)] +")"+
        "\nUSDCHF Phantom PL: $" + DoubleToStr(USDCHF_PL,2) + " (" + trend[GetQQE("USDCHF", QQE_TrendTimeframe)] +")"+
        "\nNZDUSD Phantom PL: $" + DoubleToStr(NZDUSD_PL,2) + " (" + trend[GetQQE("NZDUSD", QQE_TrendTimeframe)] +")"+
        "\nAUDJPY Phantom PL: $" + DoubleToStr(AUDJPY_PL,2) + " (" + trend[GetQQE("AUDJPY", QQE_TrendTimeframe)] +")"+
        "\nEURJPY Phantom PL: $" + DoubleToStr(EURJPY_PL,2) + " (" + trend[GetQQE("EURJPY", QQE_TrendTimeframe)] +")"+
        "\nEURUSD Phantom PL: $" + DoubleToStr(EURUSD_PL,2) + " (" + trend[GetQQE("EURUSD", QQE_TrendTimeframe)] +")"+
        "\nUSDJPY Phantom PL: $" + DoubleToStr(USDJPY_PL,2) + " (" + trend[GetQQE("USDJPY", QQE_TrendTimeframe)] +")"+
        "\nAUDUSD Phantom PL: $" + DoubleToStr(AUDUSD_PL,2) + " (" + trend[GetQQE("AUDUSD", QQE_TrendTimeframe)] +")"+
        "\nNZDJPY Phantom PL: $" + DoubleToStr(NZDJPY_PL,2) + " (" + trend[GetQQE("NZDJPY", QQE_TrendTimeframe)] +")"+
        "\nGBPCHF Phantom PL: $" + DoubleToStr(GBPCHF_PL,2) + " (" + trend[GetQQE("GBPCHF", QQE_TrendTimeframe)] +")"+
        "\nCHFJPY Phantom PL: $" + DoubleToStr(CHFJPY_PL,2) + " (" + trend[GetQQE("CHFJPY", QQE_TrendTimeframe)] +")"+
        "\nEURCHF Phantom PL: $" + DoubleToStr(EURCHF_PL,2) + " (" + trend[GetQQE("EURCHF", QQE_TrendTimeframe)] +")"+
        "\nPhantom Buy PL: $" + DoubleToStr(phantomBuyPL,2) + ",   Phantom Sell PL: $" + DoubleToStr(phantomSellPL,2) + "   Overall Phantom PL: $" + DoubleToStr(phantomEAPL,2) +
        "\nEA PL: $" + DoubleToStr(EAPL,2) + ",   Buy PL: $" + DoubleToStr(BuyPL,2) + ",   Sell PL: $" + DoubleToStr(SellPL,2) +
        "\nBiggest Winner Symbol: " + BiggestWinnerSymbol + ",   Biggest Winner Type: " + BiggestWinnerType + ",  Biggest Winner Ticket: " + DoubleToStr(BiggestWinnerTicket,0) + ",   Biggest Winner PL: $" + DoubleToStr(BiggestWinnerPL,2) +
        "\nBiggest Loser Symbol: " + BiggestLoserSymbol + ",   Biggest Loser Type: " + BiggestLoserType + ",  Biggest Loser Ticket: " + DoubleToStr(BiggestLoserTicket,0) + ",   Biggest Loser PL: $" + DoubleToStr(BiggestLoserPL,2);
        
  Comment(CommentString);

  return(0);
}


//----------------------------------------------------------------
// Get QQE Advance Trend
//----------------------------------------------------------------
int GetQQE(string fxpair, int TF) {
   double signal, main, signal_old, main_old, distance;
   
   signal = iCustom(fxpair, TF, QQEFile, QQE_SF, QQE_RSI_Period, QQE_WP, MODE_SIGNAL, 0);
   main = iCustom(fxpair, TF, QQEFile, QQE_SF, QQE_RSI_Period, QQE_WP, MODE_MAIN, 0);
   
   //signal_old = iCustom(fxpair, QQE_Timeframe, QQEFile, QQE_SF, QQE_RSI_Period, QQE_WP, MODE_SIGNAL, 0);
   //main_old = iCustom(fxpair, QQE_Timeframe, QQEFile, QQE_SF, QQE_RSI_Period, QQE_WP, MODE_MAIN, 0);
   
   // determin trend
   // rules: signal > main = SHORT / signal < main = LONG 
   // filter: if signal is getting closer to main = trend change ahead -> no signal
   
   distance = main - signal;
   if ( distance < 0 ) distance *= -1;       // if we have a negatice value
   
   if ( distance < 5 ) return (2);        // if signal and main are too narrow return RANGING
   
   if ( signal < main ) {
      return (0);                   // trend is LONG
   }
   else if ( signal > main ) {
      return (1);                   // trend is SHORT
   }
   else return (2);                 // return RANGING
}


//----------------------------------------------------------------
// TF function
// return a timeperiode as string
//----------------------------------------------------------------
string TF (int timeframe) {
   switch (timeframe) {
      case PERIOD_M1 : return ("1 min.");
      case PERIOD_M5 : return ("5 min.");
      case PERIOD_M15: return ("15 min.");
      case PERIOD_M30: return ("30 min.");
      case PERIOD_H1 : return ("1 hour");
      case PERIOD_H4 : return ("4 hours");
      case PERIOD_D1 : return ("1 day");
      case PERIOD_W1 : return ("1 week");
      case PERIOD_M1 : return ("1 month");
   }
   return ("unkown");
}


//----------------------------------------------------------------
// SinglePositionSL function
// close a position if SL hit
//----------------------------------------------------------------
void SinglePositionSL() {

   if (OrdersTotal() == 0) return (0);    // exit if no open positions
   
   for (int i=0; i<OrdersTotal(); i++) {
   
      if (OrderSelect(i, SELECT_BY_POS) && OrderMagicNumber() == MagicNumber) {
         if (OrderProfit() < 0 && ConvertProfitToPips(OrderSymbol(), OrderProfit(), OrderLots()) <= (SL_per_position * (-1))) {
            if (OrderType() == OP_BUY && GetQQE(OrderSymbol(), QQE_TrendTimeframe) == OP_SELL) {
               // position is in loss and trend is against position
               if (OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), Slippage)) {
                  Print("Closing ticket #", OrderTicket(), ", because SL hit and QQE trend is against position.");
               }
               else Print("Error closing ", OrderSymbol(),". Reason: ", GetLastError());
            }
            else if (OrderType() == OP_SELL && GetQQE(OrderSymbol(), QQE_TrendTimeframe) == OP_BUY) {
               // position is in loss and trend is against position
               if (OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), Slippage)) {
                  Print("Closing ticket #", OrderTicket(), ", because SL hit and QQE trend is against position.");
               }
               else Print("Error closing ", OrderSymbol(),". Reason: ", GetLastError());
            }
         }
      }
   }
}


//----------------------------------------------------------------
// Convert profit into pips
// close a position if SL hit
//----------------------------------------------------------------
int ConvertProfitToPips(string fxpair, double profit, double lots) {
   double tickvalue, ticksize, points, pips, nominalpoints, orderpoints;

   tickvalue = MarketInfo(fxpair, MODE_TICKVALUE);
   ticksize = MarketInfo(fxpair, MODE_TICKSIZE);
   points = MarketInfo(fxpair, MODE_POINT);
   nominalpoints = tickvalue * points / ticksize;
   orderpoints = nominalpoints * lots;
   pips = NormalizeDouble((profit/orderpoints),0);
   
   if (MarketInfo(fxpair, MODE_DIGITS) == 3 || MarketInfo(fxpair, MODE_DIGITS) == 5)
      pips *= 10;
   return (pips);
}