//+------------------------------------------------------------------+
//|                                                OpenFiboOrder.mq4 |
//|                                                                  |
//|                                              contact@mqlsoft.com |
//|                                          http://www.mqlsoft.com/ |
//+------------------------------------------------------------------+
#property copyright "MQLsoft.com"
#property link      "www.mqlsoft.com"
#property show_inputs

#include <stderror.mqh>
#include <stdlib.mqh>
#include <WinUser32.mqh>

extern double Lots = 0.1;
int MAGIC = 0;

int start() {

    int cnt;
    datetime dt;
    string fibo = "";
    
    for (cnt = ObjectsTotal() - 1; cnt >= 0; cnt--) {
        string name = ObjectName(cnt);
        if (ObjectType(name) == OBJ_FIBO) {
            if (ObjectGet(name, OBJPROP_TIME1) > dt) {
                fibo = name;
                dt = ObjectGet(name, OBJPROP_TIME1);
            }
        }
    }    

    if (fibo == "") {
        MessageBox("Fibonacci Retracement object not found!\n\nCreate one and run this script again.", "Warning", MB_OK | MB_ICONWARNING);
        return (-1);
    }
   
    double open = ObjectGet(fibo, OBJPROP_PRICE1);
    double sl = ObjectGet(fibo, OBJPROP_PRICE2);

    double tpFract = 0;
    int fiboLevels = ObjectGet(fibo, OBJPROP_FIBOLEVELS);
    for (cnt = 0; cnt < fiboLevels; cnt++) {
        tpFract = ObjectGet(fibo, OBJPROP_FIRSTLEVEL + cnt);
        if (tpFract > 1.0) {
            break;
        }
    }

    if (tpFract <= 1.0) {
        MessageBox("Fibonacci Retracement object has no level above 1.0!\n\nSet default levels in Fibonacci Retracement object and run this script again.", "Warning", MB_OK | MB_ICONWARNING);
        return (-1);    
    }
        
    if (Lots < MarketInfo(Symbol(), MODE_MINLOT)) {
        MessageBox("Choosen position size is lower than minimum permitted amount of a lot (" + DoubleToStr(MarketInfo(Symbol(), MODE_MINLOT), 2) + ")!", "Warning", MB_OK | MB_ICONWARNING);
        return (-1);    
    }        
        
    double tp = open + (tpFract - 1.0) * (open - sl);    
    int ticket, error;
    
    if (open > sl) { // buystop order
        open += getSpread(OP_BUYSTOP, 1);
        sl += getSpread(OP_SELLSTOP, 0);
        tp += getSpread(OP_SELLSTOP, 0);
        if (!checkStops(open, sl, tp)) {
            MessageBox("Fibonacci Retracement object is too small so that price levels are too close!", "Warning", MB_OK | MB_ICONWARNING);
            return (-1);
        }
        ticket = OrderSendNormalize(Symbol(), OP_BUYSTOP, Lots, open, 0, sl, tp, NULL, MAGIC);
        if (ticket < 0) {
            error = GetLastError();
            Print("OrderSend failed with error #", error);
            MessageBox("An error occurred: " + ErrorDescription(error) + ".", "Error", MB_OK | MB_ICONERROR);            
            return (0);
        }
    } else if (open < sl) { // sellstop order
        open += getSpread(OP_SELLSTOP, 1);
        sl += getSpread(OP_BUYSTOP, 0);
        tp += getSpread(OP_BUYSTOP, 0);            
        if (!checkStops(open, sl, tp)) {
            MessageBox("Fibonacci Retracement object is too small so that price levels are too close!", "Warning", MB_OK | MB_ICONWARNING);
            return (-1);
        }
        ticket = OrderSendNormalize(Symbol(), OP_SELLSTOP, Lots, open, 0, sl, tp, NULL, MAGIC);
        if (ticket < 0) {
            error = GetLastError();
            Print("OrderSend failed with error #", error);
            MessageBox("An error occurred: " + ErrorDescription(error) + ".", "Error", MB_OK | MB_ICONERROR);            
            return (0);
        }
    }

    return (0);
}

int OrderSendNormalize(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment = "", int magic = 0, datetime expiration = 0, color arrow_color = CLR_NONE) {
    return (OrderSend(symbol, cmd, volume, NormalizeDouble(price, Digits), slippage, NormalizeDouble(stoploss, Digits), NormalizeDouble(takeprofit, Digits), comment, magic, expiration, arrow_color));
}

bool checkStops(double open, double sl, double tp) {
    double minStop = MarketInfo(Symbol(), MODE_STOPLEVEL) * MarketInfo(Symbol(), MODE_POINT);    
    if (sl != 0) {
        if (MathAbs(open - sl) < minStop) {
            return (false);
        }
    }
    if (tp != 0) {
        if (MathAbs(open - tp) < minStop) {
            return (false);
        }
    }
    return (true);
}

double getSpread(int type, int marginPoints = 0) {
    if (type == OP_SELL || type == OP_SELLSTOP || type == OP_SELLLIMIT) {
        return (NormalizeDouble(- marginPoints * Point, Digits));
    } else if (type == OP_BUY || type == OP_BUYSTOP || type == OP_BUYLIMIT) {
        return (NormalizeDouble(Ask - Bid + marginPoints * Point, Digits));
    }
}