//+------------------------------------------------------------------+ //| leftbrain_v14.mq5 | //| Naguisa Unada | //| https://www.mql5.com/en/users/unadajapon/news | //+------------------------------------------------------------------+ #property copyright "Naguisa Unada" #property link "https://www.mql5.com/en/users/unadajapon/news" #property version "1.00" #property indicator_chart_window #property indicator_buffers 0 #property indicator_plots 0 #define objectPrefix "lbt" //--- input parameters input int MN1_fib_number = 1000; input int W1_fib_number = 1000; input int D1_fib_number = 1000; input int H4_fib_number = 382; input int H1_fib_number = 382; input int M30_fib_number = 236; input int M15_fib_number = 146; input int M5_fib_number = 90; input int M1_fib_number = 56; input bool showStickies = true; input int minStickies = 1; input double stickyPercentBuffer = 0.1; input int sets = 5; input int labelOffset = 15; input color frameworkColor = clrLimeGreen; input color weakLineColor = clrPurple; input color subBaselineColor = clrDeepSkyBlue; input color stickyColor = clrRed; double base = 0; int nums[6] = {56, 90, 146, 236, 382, 1000}; double fibs[8] = {0.146, 0.236, 0.382, 0.50, 0.618, 0.764, 0.854, 1}; double compareFibs[8] = {14.6, 23.6, 38.2, 50, 61.8, 76.4, 85.4, 100}; string labels[8] = {"146", "236", "382", "50", "618", "764", "854", "1000"}; int subStyles[8] = {0, 0, 2, 2, 2, 0, 0, 0}; double multiple = 1.0; double root = 0.0; int fibNumber, trimNumber; double storage[]; int basePeriod; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping int adjustment = (int)MathMod(Digits(), 2); string sym = StringSubstr(Symbol(), 0, 6); if (adjustment == 0) adjustment = 1; else adjustment = 10; multiple = Point() * adjustment; trimNumber = (int)Digits(); basePeriod = Period() * 60; if (sym == "EURUSD") root = 1.2000; else if (sym == "USDCHF") root = 1.2000; else if (sym == "USDCAD") root = 1.2000; else if (sym == "GBPUSD") root = 2.0000; else if (sym == "GBPCHF") root = 2.0000; else if (sym == "EURAUD") root = 2.0000; else if (sym == "USDJPY") root = 100.00; else if (sym == "AUDJPY") root = 100.00; else if (sym == "CHFJPY") root = 100.00; else if (sym == "CADJPY") root = 100.00; else if (sym == "NZDJPY") root = 100.00; else if (sym == "EURJPY") root = 120.00; else if (sym == "GBPJPY") root = 200.00; else if (sym == "USDCNY") root = 8.0000; else if (sym == "EURCHF") root = 1.5000; else if (sym == "AUDUSD") root = 1.0000; else if (sym == "EURGBP") root = 1.0000; else if (sym == "AUDCAD") root = 1.0000; else if (sym == "NZDUSD") root = 0.5000; else if (sym == "AUDNZD") root = 1.0000; //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { int i, objectstotal = ObjectsTotal(0); string name; for (i = objectstotal; i >= 0; i--) { name = ObjectName(0, i); if (StringFind(name, objectPrefix, 0) > -1) ObjectDelete(0, name); } } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- switch (Period()) { case PERIOD_MN1: fibNumber = MN1_fib_number; basePeriod = 2592000; break; case PERIOD_W1: fibNumber = W1_fib_number; basePeriod = 604800; break; case PERIOD_D1: fibNumber = D1_fib_number; basePeriod = 86400; break; case PERIOD_H4: fibNumber = H4_fib_number; basePeriod = 14400; break; case PERIOD_H1: fibNumber = H1_fib_number; basePeriod = 3600; break; case PERIOD_M30: fibNumber = M30_fib_number; break; case PERIOD_M15: fibNumber = M15_fib_number; break; case PERIOD_M5: fibNumber = M5_fib_number; break; case PERIOD_M1: fibNumber = M1_fib_number; } ArrayResize(storage, 0); base = findBaseline(root, close[rates_total - 1], fibNumber); int i, j, stickyCount, subStyle; int max = sets * 2; int size = ArraySize(fibs); double baseVal; double subVal; string subLabel; color subColor; for (i = -max; i < max; i++) { baseVal = base + ((fibNumber * i) * multiple); for (j = 0; j < size; j++) { subVal = baseVal + ((fibNumber * fibs[j]) * multiple); subLabel = DoubleToString(fibs[j] * 100, 1); switch (j) { case 0: subColor = weakLineColor; break; case 1: subColor = frameworkColor; break; case 5: subColor = frameworkColor; break; case 6: subColor = weakLineColor; break; case 7: ArrayResize(storage, ArraySize(storage) + 1); storage[ArraySize(storage) - 1] = baseVal; subColor = subBaselineColor; break; default: subColor = frameworkColor; break; } subStyle = subStyles[j]; string linename = objectPrefix + "-" + labels[j] + (string)i; drawHorizontalLine(linename, subVal, 1, subColor, subStyle, false); stickyCount = findStickies(subVal, fibNumber, linename); string stickyLabel; if (showStickies && stickyCount >= minStickies) { ObjectSetInteger(0, objectPrefix + labels[j] + (string)i, OBJPROP_COLOR, stickyColor); stickyLabel = " [" + (string)(stickyCount) + "]"; } else { stickyLabel = ""; } drawLabel(objectPrefix + labels[j] + "_label" + (string)i, subLabel + "% (" + DoubleToString(subVal, trimNumber) + ")" + stickyLabel, 8, "Tahoma", clrGray, time[rates_total - 1] + basePeriod * labelOffset, subVal); } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ double findBaseline(double basef, double comparePrice, int fib_number) { double diff = (comparePrice - basef); // find the difference between the current price and the baselines above double extra; if (MathAbs(diff) > (fib_number * multiple)) // if price is more than one set away, adjust base closer (for performance improvement) { extra = MathMod(diff / multiple, fib_number) * multiple; basef = basef + (diff - extra); } return (basef); } //+------------------------------------------------------------------+ void drawHorizontalLine(string name, double price, int thickness, color colour, int style, bool background) { if (ObjectFind(0, name) != 0) // if line does not already exist draw a new line ObjectCreate(0, name, OBJ_HLINE, 0, 0, price); else // if line already exists, just move the existing line ObjectSetDouble(0, name, OBJPROP_PRICE, price); ObjectSetInteger(0, name, OBJPROP_COLOR, colour); ObjectSetInteger(0, name, OBJPROP_WIDTH, thickness); ObjectSetInteger(0, name, OBJPROP_BACK, background); ObjectSetInteger(0, name, OBJPROP_STYLE, style); } //+------------------------------------------------------------------+ int findStickies(double val, int fib_number, string linename) { int i, j, fib, count = 0; int max = ArraySize(nums); int size = ArraySize(compareFibs); double closestBase, gap, ratio; string history; for (i = 0; i < max; i++) { fib = nums[i]; if (fib != fib_number) { closestBase = findBaseline(root, val, fib); gap = MathAbs(val - closestBase); ratio = (gap / (fib * multiple)) * 100; for (j = 0; j < size; j++) { double compare = compareFibs[j]; if (ratio < compare + stickyPercentBuffer && ratio > compare - stickyPercentBuffer) { if (StringLen(history) > 0) history = history + ", " + (string)(fib) + " | " + DoubleToString(100 - compare, 1) + "%"; else history = history + (string)(fib) + " | " + DoubleToString(100 - compare, 1) + "%"; count++; } } } } if (count >= minStickies && showStickies) { ObjectSetInteger(0, linename, OBJPROP_COLOR, stickyColor); clone(linename, "[" + history + "]" + " " + linename); ObjectDelete(0, linename); } return (count); } //+------------------------------------------------------------------+ void drawLabel(string name, string txt, int fontSize, string font, color colour, datetime time, double price) { if (ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_TEXT, 0, time, price); else { if (ObjectGetInteger(0, name, OBJPROP_TYPE) == OBJ_TEXT) { ObjectSetInteger(0, name, OBJPROP_TIME, time); ObjectSetDouble(0, name, OBJPROP_PRICE, price); } } ObjectSetString(0, name, OBJPROP_TEXT, txt); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize); ObjectSetString(0, name, OBJPROP_FONT, font); ObjectSetInteger(0, name, OBJPROP_COLOR, colour); } //+------------------------------------------------------------------+ void clone(string name, string cloneName) { int type = (int)ObjectGetInteger(0, name, OBJPROP_TYPE); int style, width; double price1; color objectColor; bool background; switch (type) { case OBJ_HLINE: price1 = ObjectGetDouble(0, name, OBJPROP_PRICE); objectColor = (color)ObjectGetInteger(0, name, OBJPROP_COLOR); style = (int)ObjectGetInteger(0, name, OBJPROP_STYLE); width = (int)ObjectGetInteger(0, name, OBJPROP_WIDTH); background = ObjectGetInteger(0, name, OBJPROP_BACK); drawHorizontalLine(cloneName, price1, width, objectColor, style, background); } } //+------------------------------------------------------------------+