#property copyright "Copyright 2013, Zoltan Tarsoly"
#property link "tarsolyz@t-online.hu"

extern bool draw_patterns = true;
extern int session_first_hour = 9;
extern int session_last_hour = 17;
extern int magic_number = 9999;
extern color upper_pattern_color = Blue;
extern color lower_pattern_color = Red;
extern color joint_pattern_color = Magenta;
extern double extra_price = 0.00010;
extern double spread_price = 0.00015;
extern double risk_to_reward_ratio = 1.0;
extern double maximum_risk_factor = 0.01;

datetime last_run_time;
string trendline_names[4] = {"Long 123 Pattern 2nd Leg", "Long 123 Pattern 1st Leg", "Short 123 Pattern 2nd Leg", "Short 123 Pattern 1st Leg"};

int init() {
  return(0);
}

int deinit() {
  return(0);
}

double GetPositionSize(double open_price, double stop_loss_price) {
  double lot_step = MarketInfo(Symbol(), MODE_LOTSTEP);
  double maximum_lot = MarketInfo(Symbol(), MODE_MAXLOT);
  double minimum_lot = MarketInfo(Symbol(), MODE_MINLOT);
  double position_size = MathFloor(((AccountBalance() * maximum_risk_factor) / (((MathAbs(open_price - stop_loss_price) / MarketInfo(Symbol(), MODE_TICKSIZE)) * MarketInfo(Symbol(), MODE_TICKVALUE)))) / lot_step) * lot_step;
  if (position_size < minimum_lot)
    return(minimum_lot);
  if (position_size > maximum_lot)
    return(maximum_lot);
  return(position_size);
}

void SetPatterns(int& pattern_indexies[2][3], int last_bar_index) {
  bool is_long_pattern_completed;
  bool is_short_pattern_completed;
  int i = 3;
  ArrayInitialize(pattern_indexies, -1);
  while (i <= last_bar_index) {
    if (iFractals(NULL, 0, MODE_UPPER, i) > 0) {
      if ((pattern_indexies[0][0] >= 0) && ((pattern_indexies[0][1] < 0) || (High[i] > High[pattern_indexies[0][1]])) && (pattern_indexies[0][2] < 0) && (i != pattern_indexies[0][0]))
        pattern_indexies[0][1] = i;
      if ((pattern_indexies[1][0] < 0) || ((pattern_indexies[1][0] >= 0) && (pattern_indexies[1][1] < 0) && (High[i] > High[pattern_indexies[1][0]])))
        pattern_indexies[1][0] = i;
      else if ((((pattern_indexies[1][1] >= 0) && (pattern_indexies[1][2] < 0) && (High[i] > High[pattern_indexies[1][0]]) && (i != pattern_indexies[1][1]))) || (!is_short_pattern_completed && (pattern_indexies[1][2] >= 0) && (High[i] > High[pattern_indexies[1][2]])))
        pattern_indexies[1][2] = i;
      else if ((pattern_indexies[1][2] >= 0) && (High[i] <= High[pattern_indexies[1][2]]))
        is_short_pattern_completed = true;
    }
    if (iFractals(NULL, 0, MODE_LOWER, i) > 0) {
      if ((pattern_indexies[1][0] >= 0) && ((pattern_indexies[1][1] < 0) || (Low[i] < Low[pattern_indexies[1][1]])) && (pattern_indexies[1][2] < 0) && (i != pattern_indexies[1][0]))
        pattern_indexies[1][1] = i;
      if ((pattern_indexies[0][0] < 0) || ((pattern_indexies[0][0] >= 0) && (pattern_indexies[0][1] < 0) && (Low[i] < Low[pattern_indexies[0][0]])))
        pattern_indexies[0][0] = i;
      else if ((((pattern_indexies[0][1] >= 0) && (pattern_indexies[0][2] < 0) && (Low[i] < Low[pattern_indexies[0][0]]) && (i != pattern_indexies[0][1])))  || (!is_long_pattern_completed && (pattern_indexies[0][2] >= 0) && (Low[i] < Low[pattern_indexies[0][2]])))
        pattern_indexies[0][2] = i;
      else if ((pattern_indexies[0][2] >= 0) && (Low[i] >= Low[pattern_indexies[0][2]]))
        is_long_pattern_completed = true;
    }
    if (is_long_pattern_completed && is_short_pattern_completed)
      break;
    i++;
  }
  if (draw_patterns) {
    if (ObjectFind(trendline_names[0]) >= 0)
      ObjectDelete(trendline_names[0]);
    ObjectCreate(trendline_names[0], OBJ_TREND, 0, Time[pattern_indexies[0][1]], High[pattern_indexies[0][1]], Time[pattern_indexies[0][0]], Low[pattern_indexies[0][0]]);
    if ((pattern_indexies[0][0] == pattern_indexies[1][1]) && (pattern_indexies[0][1] == pattern_indexies[1][2]))
      ObjectSet(trendline_names[0], OBJPROP_COLOR, joint_pattern_color);
    else
      ObjectSet(trendline_names[0], OBJPROP_COLOR, upper_pattern_color);
    ObjectSet(trendline_names[0], OBJPROP_RAY, 0);
    if (ObjectFind(trendline_names[1]) >= 0)
      ObjectDelete(trendline_names[1]);
    ObjectCreate(trendline_names[1], OBJ_TREND, 0, Time[pattern_indexies[0][2]], Low[pattern_indexies[0][2]], Time[pattern_indexies[0][1]], High[pattern_indexies[0][1]]);
    if ((pattern_indexies[0][1] == pattern_indexies[1][0]) && (pattern_indexies[0][2] == pattern_indexies[1][1]))
      ObjectSet(trendline_names[1], OBJPROP_COLOR, joint_pattern_color);
    else
      ObjectSet(trendline_names[1], OBJPROP_COLOR, upper_pattern_color);
    ObjectSet(trendline_names[1], OBJPROP_RAY, 0);
    if (ObjectFind(trendline_names[2]) >= 0)
      ObjectDelete(trendline_names[2]);
    ObjectCreate(trendline_names[2], OBJ_TREND, 0, Time[pattern_indexies[1][1]], Low[pattern_indexies[1][1]], Time[pattern_indexies[1][0]], High[pattern_indexies[1][0]]);
    if ((pattern_indexies[1][0] == pattern_indexies[0][1]) && (pattern_indexies[1][1] == pattern_indexies[0][2]))
      ObjectSet(trendline_names[2], OBJPROP_COLOR, joint_pattern_color);
    else
      ObjectSet(trendline_names[2], OBJPROP_COLOR, lower_pattern_color);
    ObjectSet(trendline_names[2], OBJPROP_RAY, 0);
    if (ObjectFind(trendline_names[3]) >= 0)
      ObjectDelete(trendline_names[3]);
    ObjectCreate(trendline_names[3], OBJ_TREND, 0, Time[pattern_indexies[1][2]], High[pattern_indexies[1][2]], Time[pattern_indexies[1][1]], Low[pattern_indexies[1][1]]);
    if ((pattern_indexies[1][1] == pattern_indexies[0][0]) && (pattern_indexies[1][2] == pattern_indexies[0][1]))
      ObjectSet(trendline_names[3], OBJPROP_COLOR, joint_pattern_color);
    else
      ObjectSet(trendline_names[3], OBJPROP_COLOR, lower_pattern_color);
    ObjectSet(trendline_names[3], OBJPROP_RAY, 0);
  }
}

int start() {
  bool have_buy_order;
  bool have_sell_order;
  bool is_trade_time = (TimeHour(Time[0]) >= session_first_hour) && (TimeHour(Time[0]) <= session_last_hour);
  int i;
  int ticket;
  int pattern_indexies[2][3] = {-1, -1, -1, -1, -1, -1};
  double open_price;
  double stop_loss_price;
  double take_profit_price;
  if (last_run_time < Time[0]) {
    last_run_time = Time[0];
    SetPatterns(pattern_indexies, Bars - 1);
    for (i = OrdersTotal() - 1; i >= 0; i--)
      if (OrderSelect(i, SELECT_BY_POS)) {
        if (OrderMagicNumber() == magic_number)
          switch (OrderType()) {
            case OP_BUY:
              have_buy_order = true;
              break;
            case OP_BUYSTOP:
              have_buy_order = true;
              if ((High[pattern_indexies[0][1]] > High[iHighest(NULL, 0, pattern_indexies[0][1], 0)]) && (High[pattern_indexies[0][1]] > iMA(NULL, 0, 34, 0, MODE_EMA, PRICE_HIGH, pattern_indexies[0][1])) && (High[pattern_indexies[0][1]] > iMA(NULL, 0, 89, 0, MODE_EMA, PRICE_CLOSE, pattern_indexies[0][1])) && is_trade_time) {
                open_price = NormalizeDouble(High[pattern_indexies[0][1]] + spread_price + extra_price, Digits);
                stop_loss_price = NormalizeDouble(Low[pattern_indexies[0][2]] - extra_price, Digits);
                take_profit_price = NormalizeDouble(open_price + (open_price - stop_loss_price) / risk_to_reward_ratio, Digits);
                if ((open_price != NormalizeDouble(OrderOpenPrice(), Digits)) || (stop_loss_price != NormalizeDouble(OrderStopLoss(), Digits)) || (take_profit_price != NormalizeDouble(OrderTakeProfit(), Digits)))
                  if (!OrderModify(OrderTicket(), open_price, stop_loss_price, take_profit_price, 0))
                    Alert("Error: OrderModify!");
              }
              /*else
                if (!OrderDelete(OrderTicket()))
                  Alert("Error: OrderDelete!");*/
              break;
            case OP_SELL:
              have_sell_order = true;
              break;
            case OP_SELLSTOP:
              have_sell_order = true;
              if ((Low[pattern_indexies[1][1]] < Low[iLowest(NULL, 0, pattern_indexies[1][1], 0)]) && (Low[pattern_indexies[1][1]] < iMA(NULL, 0, 34, 0, MODE_EMA, PRICE_LOW, pattern_indexies[1][1])) && (Low[pattern_indexies[1][1]] < iMA(NULL, 0, 89, 0, MODE_EMA, PRICE_CLOSE, pattern_indexies[1][1])) && is_trade_time) {
                open_price = NormalizeDouble(Low[pattern_indexies[1][1]] - extra_price, Digits);
                stop_loss_price = NormalizeDouble(High[pattern_indexies[1][2]] + spread_price + extra_price, Digits);
                take_profit_price = NormalizeDouble(open_price - (stop_loss_price - open_price) / risk_to_reward_ratio + spread_price, Digits);
                if ((open_price != NormalizeDouble(OrderOpenPrice(), Digits)) || (stop_loss_price != NormalizeDouble(OrderStopLoss(), Digits)) || (take_profit_price != NormalizeDouble(OrderTakeProfit(), Digits)))
                  if (!OrderModify(OrderTicket(), open_price, stop_loss_price, take_profit_price, 0))
                    Alert("Error: OrderModify!");
              }
              /*else
                if (!OrderDelete(OrderTicket()))
                  Alert("Error: OrderDelete!");*/
              break;
          }
      }
      else
        Alert("Error: OrderSelect!");
    if ((High[pattern_indexies[0][1]] > High[iHighest(NULL, 0, pattern_indexies[0][1], 0)]) && (High[pattern_indexies[0][1]] > iMA(NULL, 0, 34, 0, MODE_EMA, PRICE_HIGH, pattern_indexies[0][1])) && (High[pattern_indexies[0][1]] > iMA(NULL, 0, 89, 0, MODE_EMA, PRICE_CLOSE, pattern_indexies[0][1])) && is_trade_time && !have_buy_order) {
      open_price = NormalizeDouble(High[pattern_indexies[0][1]] + spread_price + extra_price, Digits);
      stop_loss_price = NormalizeDouble(Low[pattern_indexies[0][2]] - extra_price, Digits);
      take_profit_price = NormalizeDouble(open_price + (open_price - stop_loss_price) / risk_to_reward_ratio, Digits);
      ticket = OrderSend(Symbol(), OP_BUYSTOP, GetPositionSize(open_price, stop_loss_price), open_price, 0, stop_loss_price, take_profit_price, NULL, magic_number);
      if (ticket < 0)
        Alert("Error: OrderSend!");
    }
    if ((Low[pattern_indexies[1][1]] < Low[iLowest(NULL, 0, pattern_indexies[1][1], 0)]) && (Low[pattern_indexies[1][1]] < iMA(NULL, 0, 34, 0, MODE_EMA, PRICE_LOW, pattern_indexies[1][1])) && (Low[pattern_indexies[1][1]] < iMA(NULL, 0, 89, 0, MODE_EMA, PRICE_CLOSE, pattern_indexies[1][1])) && is_trade_time && !have_sell_order) {
      open_price = NormalizeDouble(Low[pattern_indexies[1][1]] - extra_price, Digits);
      stop_loss_price = NormalizeDouble(High[pattern_indexies[1][2]] + spread_price + extra_price, Digits);
      take_profit_price = NormalizeDouble(open_price - (stop_loss_price - open_price) / risk_to_reward_ratio + spread_price, Digits);
      ticket = OrderSend(Symbol(), OP_SELLSTOP, GetPositionSize(open_price, stop_loss_price), open_price, 0, stop_loss_price, take_profit_price, NULL, magic_number);
      if (ticket < 0)
        Alert("Error: OrderSend!");
    }
  }
  return(0);
}

