
#property copyright "© 2011 BJF Trading Group"
#property link      "www.iticsoftware.com"

#define vers   "1.0"


extern string _tmp1_ = " --- Trade params ---";
extern int    AccDigits = 5;
extern bool   SupportECN = false;
extern bool   AllowLongs = true;
extern bool   AllowShorts = true;
extern double Lots = 0.1;
extern int    StopLoss = 100;
extern int    TakeProfit = 100;
extern bool   ReverseSignals = false;
extern int    Slippage = 3;
extern int    Magic = 20110422;


extern string _tmp2_ = " --- Parabolic SAR ---";
extern double PSAR.step = 0.02;
extern double PSAR.maximum = 0.2;
extern int    PSAR.SignalBar = 0;


extern string _tmp3_ = " --- Chart ---";
extern color clBuy = DodgerBlue;
extern color clSell = Red;
extern color clClose = Gold;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <stdlib.mqh>
#include <stderror.mqh>

int RepeatN = 5;

int BuyCnt, SellCnt;
int BuyStopCnt, SellStopCnt;
int BuyLimitCnt, SellLimitCnt;

void init() 
{
}

void deinit() 
{
}

void start() 
{
  if (IsTradeContextBusy())
  {
    Print("TradeContext is busy, pause...");
    return;
  }

  //-----  

  double PSAR1 = iSAR(NULL, 0, PSAR.step, PSAR.maximum, PSAR.SignalBar);
  double PSAR2 = iSAR(NULL, 0, PSAR.step, PSAR.maximum, PSAR.SignalBar+1);
  
  bool BuyCond = (PSAR1 < Close[PSAR.SignalBar] && PSAR2 >= Close[PSAR.SignalBar+1]);
  bool SellCond = (PSAR1 > Close[PSAR.SignalBar] && PSAR2 <= Close[PSAR.SignalBar+1]);
  
    
  if (ReverseSignals)
  {
    bool bTmp = BuyCond;
    BuyCond = SellCond;
    SellCond = bTmp;
  }
  
  //-----
  
  RecountOrders();  

  if (OrdersCountBar0(0) > 0) return;
  
  //-----
     
  double lot;
  int ticket;
  string comment;

  if (BuyCond)
  {
    if (BuyCnt > 0) return;
    if (CloseOrders(OP_SELL) > 0) return;
    
    if (!AllowLongs) return;
    
    //-----
    
    lot = GetLots();
    comment = "";
    
    ticket = BuyEx(Symbol(), lot, 0, StopLoss, 0, TakeProfit, Magic, comment);

    return;
  }

  if (SellCond)
  {
    if (SellCnt > 0) return;
    if (CloseOrders(OP_BUY) > 0) return;
    
    if (!AllowShorts) return;
    
    //-----
  
    lot = GetLots();
    comment = "";
    
    ticket = SellEx(Symbol(), lot, 0, StopLoss, 0, TakeProfit, Magic, comment);

    return;
  } 
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

double If(bool cond, double if_true, double if_false)
{
  if (cond) return (if_true);
  return (if_false);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

double PointEx()
{
  if (AccDigits == 5) return (10*Point);
  
  return (Point);
}

int fpc()
{
  if (AccDigits == 5) return (10);
  if (AccDigits == 6) return (100);
  
  return (1); 
}

double GetLots() 
{ 
  return (Lots);
}

void RecountOrders()
{
  BuyCnt = 0;
  SellCnt = 0;
  BuyStopCnt = 0;
  SellStopCnt = 0;
  BuyLimitCnt = 0;
  SellLimitCnt = 0;

  int cnt = OrdersTotal();
  for (int i=0; i < cnt; i++) 
  {
    if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
    if (OrderSymbol() != Symbol()) continue;
    if (OrderMagicNumber() != Magic) continue;
    
    int type = OrderType();
    if (type == OP_BUY) BuyCnt++;
    if (type == OP_SELL) SellCnt++;
    if (type == OP_BUYSTOP) BuyStopCnt++;
    if (type == OP_SELLSTOP) SellStopCnt++;
    if (type == OP_BUYLIMIT) BuyLimitCnt++;
    if (type == OP_SELLLIMIT) SellLimitCnt++;
  }
}

int OrdersCountBar0(int TF)
{
  int orders = 0;

  int cnt = OrdersTotal();
  for (int i=0; i<cnt; i++) 
  {
    if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
    if (OrderSymbol() != Symbol()) continue;
    if (OrderMagicNumber() != Magic) continue;

    if (OrderOpenTime() >= iTime(NULL, TF, 0)) orders++;
  }

  cnt = OrdersHistoryTotal();
  for (i=0; i<cnt; i++) 
  {
    if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue;
    if (OrderSymbol() != Symbol()) continue;
    if (OrderMagicNumber() != Magic) continue;

    if (OrderOpenTime() >= iTime(NULL, TF, 0)) orders++;
  }
 
  return (orders);
}

int CloseOrders(int type1, int type2 = -1) 
{  
  int cnt = OrdersTotal();
  for (int i=cnt-1; i >= 0; i--) 
  {
    if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
    if (OrderSymbol() != Symbol()) continue;
    if (OrderMagicNumber() != Magic) continue;
    
    int type = OrderType();
    if (type != type1 && type != type2) continue;
    
    if (type == OP_BUY) 
    {
      RefreshRates();
      CloseOrder(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID));
      continue;
    }
    
    if (type == OP_SELL) 
    {
      RefreshRates();
      CloseOrder(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK));
      continue;
    }    
  }
  
  int orders = 0;
  cnt = OrdersTotal();
  for (i = 0; i < cnt; i++) 
  {
    if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
    if (OrderSymbol() != Symbol()) continue;
    if (OrderMagicNumber() != Magic) continue;
    
    type = OrderType();
    if (type != type1 && type != type2) continue;
    
    orders++;
  }
  
  return (orders); 
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

int SleepOk = 500;
int SleepErr = 2000;

int Buy(string symbol, double lot, double price, double sl, double tp, int magic, string comment="") 
{
  int dig = MarketInfo(symbol, MODE_DIGITS);

  price = NormalizeDouble(price, dig);
  sl = NormalizeDouble(sl, dig);
  tp = NormalizeDouble(tp, dig);
    
  string _lot = DoubleToStr(lot, 2);
  string _price = DoubleToStr(price, dig);
  string _sl = DoubleToStr(sl, dig);
  string _tp = DoubleToStr(tp, dig);

  Print("Buy \"", symbol, "\", ", _lot, ", ", _price, ", ", Slippage*fpc(), ", ", _sl, ", ", _tp, ", ", magic, ", \"", comment, "\"");

  int res = OrderSend(symbol, OP_BUY, lot, price, Slippage*fpc(), sl, tp, comment, magic, 0, clBuy);
  if (res >= 0) {
    Sleep(SleepOk);
    return (res);
  } 	
   	
  int code = GetLastError();
  Print("Error opening BUY order: ", ErrorDescription(code), " (", code, ")");
  Sleep(SleepErr);
	
  return (-1);
}

int Sell(string symbol, double lot, double price, double sl, double tp, int magic, string comment="") 
{
  int dig = MarketInfo(symbol, MODE_DIGITS);

  price = NormalizeDouble(price, dig);
  sl = NormalizeDouble(sl, dig);
  tp = NormalizeDouble(tp, dig);
  
  string _lot = DoubleToStr(lot, 2);
  string _price = DoubleToStr(price, dig);
  string _sl = DoubleToStr(sl, dig);
  string _tp = DoubleToStr(tp, dig);

  Print("Sell \"", symbol, "\", ", _lot, ", ", _price, ", ", Slippage*fpc(), ", ", _sl, ", ", _tp, ", ", magic, ", \"", comment, "\"");
  
  int res = OrderSend(symbol, OP_SELL, lot, price, Slippage*fpc(), sl, tp, comment, magic, 0, clSell);
  if (res >= 0) {
    Sleep(SleepOk);
    return (res);
  } 	
   	
  int code = GetLastError();
  Print("Error opening SELL order: ", ErrorDescription(code), " (", code, ")");
  Sleep(SleepErr);
	
  return (-1);
}

int BuyEx(string symbol, double lot, double sl, int sl.pips, double tp, int tp.pips, int magic, string comment="")
{
  int ticket;
  double price;
  bool res;
  
  if (SupportECN)
  {
    for (int i=0; i<RepeatN; i++)
    {
      RefreshRates();
      price = Ask;
      
      ticket = Buy(symbol, lot, price, 0, 0, magic, comment);
      if (ticket > 0) break;
    }

    if (ticket > 0)
    {
      OrderSelect(ticket, SELECT_BY_TICKET);
      price = OrderOpenPrice();

      if (sl == 0.0) sl = If(sl.pips > 0, price - sl.pips*PointEx(), 0);
      if (tp == 0.0) tp = If(tp.pips > 0, price + tp.pips*PointEx(), 0);
    
      if (sl > 0 || tp > 0)
      {
        for (i=0; i<3*RepeatN; i++)
        {
          res = OrderModify(ticket, OrderOpenPrice(), sl, tp, 0);
          if (res) break;
          
          Sleep(SleepErr);
        }
      }
    }
  }
  
  else
  {
    for (i=0; i<RepeatN; i++)
    {
      RefreshRates();
      price = Ask;

      if (sl == 0.0) sl = If(sl.pips > 0, price - sl.pips*PointEx(), 0);
      if (tp == 0.0) tp = If(tp.pips > 0, price + tp.pips*PointEx(), 0);

      ticket = Buy(symbol, lot, price, sl, tp, magic, comment);
      if (ticket > 0) break;
    }
  }
}

int SellEx(string symbol, double lot, double sl, int sl.pips, double tp, int tp.pips, int magic, string comment="")
{
  int ticket;
  double price;
  bool res;
  
  if (SupportECN)
  {
    for (int i=0; i<RepeatN; i++)
    {
      RefreshRates();
      price = Bid;
      
      ticket = Sell(symbol, lot, price, 0, 0, magic, comment);
      if (ticket > 0) break;
    }

    if (ticket > 0)
    {
      OrderSelect(ticket, SELECT_BY_TICKET);
      price = OrderOpenPrice();

      if (sl == 0.0) sl = If(sl.pips > 0, price + sl.pips*PointEx(), 0);
      if (tp == 0.0) tp = If(tp.pips > 0, price - tp.pips*PointEx(), 0);
    
      if (sl > 0 || tp > 0)
      {
        for (i=0; i<3*RepeatN; i++)
        {
          res = OrderModify(ticket, OrderOpenPrice(), sl, tp, 0);
          if (res) break;
          
          Sleep(SleepErr);       
        }
      }
    }
  }
  
  else
  {
    for (i=0; i<RepeatN; i++)
    {
      RefreshRates();
      price = Bid;

      if (sl == 0.0) sl = If(sl.pips > 0, price + sl.pips*PointEx(), 0);
      if (tp == 0.0) tp = If(tp.pips > 0, price - tp.pips*PointEx(), 0);

      ticket = Sell(symbol, lot, price, sl, tp, magic, comment);
      if (ticket > 0) break;
    }
  }
}

bool CloseOrder(int ticket, double lot, double price) 
{
  if (!OrderSelect(ticket, SELECT_BY_TICKET)) return(false);
  if (OrderCloseTime() > 0) return(false);
  
  int dig = MarketInfo(OrderSymbol(), MODE_DIGITS);
  string _lot = DoubleToStr(lot, 2);
  string _price = DoubleToStr(price, dig);

  Print("CloseOrder ", ticket, ", ", _lot, ", ", _price, ", ", Slippage*fpc());
  
  bool res = OrderClose(ticket, lot, price, Slippage*fpc(), clClose);
  if (res) {
    Sleep(SleepOk);
    return (res);
  } 	
   	
  int code = GetLastError();
  Print("CloseOrder failed: ", ErrorDescription(code), " (", code, ")");
  Sleep(SleepErr);
	
  return (false);
}