// More information about this indicator can be found at: // https://fxcodebase.com/code/viewtopic.php?f=38&t=69580 //+------------------------------------------------------------------------+ //| Copyright © 2021, Gehtsoft USA LLC | //| http://fxcodebase.com | //+------------------------------------------------------------------------+ //| Support our efforts by donating | //| Paypal: https://goo.gl/9Rj74e | //+------------------------------------------------------------------------+ //| Developed by : Mario Jemic | //| mario.jemic@gmail.com | //| https://AppliedMachineLearning.systems | //| Patreon : https://goo.gl/GdXWeN | //+------------------------------------------------------------------------+ //+------------------------------------------------------------------------+ //|BitCoin Address : 15VCJTLaz12Amr7adHSBtL9v8XomURo9RF | //|Ethereum Address : 0x8C110cD61538fb6d7A2B47858F0c0AaBd663068D | //|Dogecoin Address : DNDTFfmVa2Gjts5YvSKEYaiih6cums2L6C | //|Binance(ERC20 & BSC only) : 0xe84751063de8ade7c5fbff5e73f6502f02af4e2c | //|Binance Address (BEP2 only): bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23 | //|Binance MEMO (BEP2 only) : 107152697 | //|LiteCoin Address : LLU8PSY2vsq7B9kRELLZQcKf5nJQrdeqwD | //+------------------------------------------------------------------------+ #property copyright "Copyright © 2021, Gehtsoft USA LLC" #property link "http://fxcodebase.com" #property version "1.0" #property indicator_separate_window #property strict input int tenkan_sen = 9; // Tenkan-sen input int kijun_sen = 26; // Kijun-sen input int senkou_span_b = 52; // Senkou Span B enum DisplayMode { Vertical, Horizontal }; input string Comment1 = "- Comma Separated Pairs - Ex: EURUSD,EURJPY,GBPUSD - "; input string Pairs = "EURUSD,EURJPY,USDJPY,GBPUSD"; input bool Include_M1 = false; input bool Include_M5 = false; input bool Include_M15 = false; input bool Include_M30 = false; input bool Include_H1 = true; input bool Include_H4 = false; input bool Include_D1 = true; input bool Include_W1 = true; input bool Include_MN1 = false; input color Labels_Color = clrWhite; // Labels color input color button_text_color = Black; // Button text color input int min_button_width = 30; // Min button width #ifdef USE_HISTORIC input color historical_Up_Color = Green; // Historical up color #else color historical_Up_Color = Green; // Historical up color #endif input color Up_Color = Lime; // Up color #ifdef USE_HISTORIC input color historical_Dn_Color = Red; // Historical down color #else color historical_Dn_Color = Red; // Historical down color #endif input color Dn_Color = Pink; // Down color input color neutral_color = clrDarkGray; // Neutral color input int x_shift = 900; // X coordinate input ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER; // Corner input DisplayMode display_mode = Vertical; // Display mode input int font_size = 10; // Font Size; input int cell_width = 80; // Cell width input int cell_height = 30; // Cell height input bool alert_on_close = false; // Alert on bar close #define MAX_LOOPBACK 500 string WindowName; // Base condition v1.1 #ifndef ABaseCondition_IMP #define ABaseCondition_IMP // Condition base v2.1 #ifndef ACondition_IMP #define ACondition_IMP // ICondition v3.0 #ifndef ICondition_IMP #define ICondition_IMP interface ICondition { public: virtual void AddRef() = 0; virtual void Release() = 0; virtual bool IsPass(const int period, const datetime date) = 0; virtual string GetLogMessage(const int period, const datetime date) = 0; }; #endif class AConditionBase : public ICondition { int _references; string _conditionName; public: AConditionBase(string name = "") { _conditionName = name; _references = 1; } virtual void AddRef() { ++_references; } virtual void Release() { --_references; if (_references == 0) delete &this; } virtual string GetLogMessage(const int period, const datetime date) { if (_conditionName == "" || _conditionName == NULL) { return ""; } return _conditionName + ": " + (IsPass(period, date) ? "true" : "false"); } }; #endif // Symbol info v1.3 #ifndef InstrumentInfo_IMP #define InstrumentInfo_IMP class InstrumentInfo { string _symbol; double _mult; double _point; double _pipSize; int _digit; double _ticksize; public: InstrumentInfo(const string symbol) { _symbol = symbol; _point = SymbolInfoDouble(symbol, SYMBOL_POINT); _digit = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); _mult = _digit == 3 || _digit == 5 ? 10 : 1; _pipSize = _point * _mult; _ticksize = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE), _digit); } // Return < 0 when lot1 < lot2, > 0 when lot1 > lot2 and 0 owtherwise int CompareLots(double lot1, double lot2) { double lotStep = SymbolInfoDouble(_symbol, SYMBOL_VOLUME_STEP); if (lotStep == 0) { return lot1 < lot2 ? -1 : (lot1 > lot2 ? 1 : 0); } int lotSteps1 = (int)floor(lot1 / lotStep + 0.5); int lotSteps2 = (int)floor(lot2 / lotStep + 0.5); int res = lotSteps1 - lotSteps2; return res; } static double GetPipSize(const string symbol) { double point = SymbolInfoDouble(symbol, SYMBOL_POINT); double digit = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); double mult = digit == 3 || digit == 5 ? 10 : 1; return point * mult; } double GetPointSize() { return _point; } double GetPipSize() { return _pipSize; } int GetDigits() { return _digit; } string GetSymbol() { return _symbol; } static double GetBid(const string symbol) { return SymbolInfoDouble(symbol, SYMBOL_BID); } static double GetAsk(const string symbol) { return SymbolInfoDouble(symbol, SYMBOL_ASK); } double GetBid() { return SymbolInfoDouble(_symbol, SYMBOL_BID); } double GetAsk() { return SymbolInfoDouble(_symbol, SYMBOL_ASK); } double GetMinLots() { return SymbolInfoDouble(_symbol, SYMBOL_VOLUME_MIN); }; double RoundRate(const double rate) { return NormalizeDouble(MathRound(rate / _ticksize) * _ticksize, _digit); } double RoundLots(const double lots) { double lotStep = SymbolInfoDouble(_symbol, SYMBOL_VOLUME_STEP); if (lotStep == 0) { return 0.0; } return floor(lots / lotStep) * lotStep; } double LimitLots(const double lots) { double minVolume = GetMinLots(); if (minVolume > lots) { return 0.0; } double maxVolume = SymbolInfoDouble(_symbol, SYMBOL_VOLUME_MAX); if (maxVolume < lots) { return maxVolume; } return lots; } double NormalizeLots(const double lots) { return LimitLots(RoundLots(lots)); } }; #endif class ACondition : public AConditionBase { protected: ENUM_TIMEFRAMES _timeframe; InstrumentInfo* _instrument; string _symbol; public: ACondition(const string symbol, ENUM_TIMEFRAMES timeframe, string name = NULL) :AConditionBase(name) { _instrument = new InstrumentInfo(symbol); _timeframe = timeframe; _symbol = symbol; } ~ACondition() { delete _instrument; } }; #endif class UpCondition : public ACondition { int _indi; public: UpCondition(const string symbol, ENUM_TIMEFRAMES timeframe) :ACondition(symbol, timeframe) { _indi = iIchimoku(_symbol, _timeframe, tenkan_sen, kijun_sen, senkou_span_b); } ~UpCondition() { IndicatorRelease(_indi); } virtual bool IsPass(const int period, const datetime date) { double tenkan[1]; if (CopyBuffer(_indi, 0, period, 1, tenkan) != 1) { return false; } double kijun[1]; if (CopyBuffer(_indi, 1, period, 1, kijun) != 1) { return false; } double a[1]; if (CopyBuffer(_indi, 2, period, 1, a) != 1) { return false; } double b[1]; if (CopyBuffer(_indi, 1, period, 1, b) != 1) { return false; } return MathAbs(tenkan[0] - kijun[0]) < MathAbs(a[0] - b[0]); } }; class DownCondition : public ACondition { int _indi; public: DownCondition(const string symbol, ENUM_TIMEFRAMES timeframe) :ACondition(symbol, timeframe) { _indi = iIchimoku(_symbol, _timeframe, tenkan_sen, kijun_sen, senkou_span_b); } ~DownCondition() { IndicatorRelease(_indi); } virtual bool IsPass(const int period, const datetime date) { double tenkan[1]; if (CopyBuffer(_indi, 0, period, 1, tenkan) != 1) { return false; } double kijun[1]; if (CopyBuffer(_indi, 1, period, 1, kijun) != 1) { return false; } double a[1]; if (CopyBuffer(_indi, 2, period, 1, a) != 1) { return false; } double b[1]; if (CopyBuffer(_indi, 1, period, 1, b) != 1) { return false; } return MathAbs(tenkan[0] - kijun[0]) > MathAbs(a[0] - b[0]); } }; ICondition* CreateUpCondition(string symbol, ENUM_TIMEFRAMES timeframe) { return new UpCondition(symbol, timeframe); } ICondition* CreateDownCondition(string symbol, ENUM_TIMEFRAMES timeframe) { return new DownCondition(symbol, timeframe); } // Dashboard v.1.2 class Iterator { int _initialValue; int _shift; int _current; public: Iterator(int initialValue, int shift) { _initialValue = initialValue; _shift = shift; _current = _initialValue - _shift; } int GetNext() { _current += _shift; return _current; } }; // Empty cell v1.0 // Interface for a cell v1.0 #ifndef ICell_IMP #define ICell_IMP class ICell { public: virtual void Draw() = 0; protected: void ObjectMakeLabel(string nm, int xoff, int yoff, string LabelTexto, color LabelColor, int LabelCorner=1, int Window = 0, string Font = "Arial", int FSize = 8) { ObjectDelete(0, nm); ObjectCreate(0, nm, OBJ_LABEL, Window, 0, 0); ObjectSetInteger(0, nm, OBJPROP_CORNER, LabelCorner); ObjectSetInteger(0, nm, OBJPROP_XDISTANCE, xoff); ObjectSetInteger(0, nm, OBJPROP_YDISTANCE, yoff); ObjectSetInteger(0, nm, OBJPROP_BACK, false); ObjectSetString(0, nm, OBJPROP_TEXT, LabelTexto); ObjectSetInteger(0, nm, OBJPROP_BACK, false); ObjectSetString(0, nm, OBJPROP_LEVELTEXT,LabelTexto); ObjectSetString(0, nm, OBJPROP_FONT, Font); ObjectSetInteger(0, nm, OBJPROP_FONTSIZE, FSize); ObjectSetInteger(0, nm, OBJPROP_COLOR, LabelColor); } }; #endif #ifndef EmptyCell_IMP #define EmptyCell_IMP class EmptyCell : public ICell { public: virtual void Draw() { } }; #endif // Label cell v2.0 #ifndef LabelCell_IMP #define LabelCell_IMP class LabelCell : public ICell { string _id; string _text; int _x; int _y; ENUM_BASE_CORNER _corner; public: LabelCell(const string id, const string text, const int x, const int y, ENUM_BASE_CORNER __corner) { _corner = __corner; _id = id; _text = text; _x = x; _y = y; } virtual void Draw() { ObjectMakeLabel(_id, _x, _y, _text, Labels_Color, _corner, ChartWindowFind(), "Arial", font_size); } virtual void HandleButtonClicks() { } }; #endif // Grid v1.0 // Row v1.0 #ifndef Row_IMP #define Row_IMP class Row { ICell *_cells[]; public: ~Row() { int count = ArraySize(_cells); for (int i = 0; i < count; ++i) { delete _cells[i]; } } void Draw() { int count = ArraySize(_cells); for (int i = 0; i < count; ++i) { _cells[i].Draw(); } } void Add(ICell *cell) { int count = ArraySize(_cells); ArrayResize(_cells, count + 1); _cells[count] = cell; } }; #endif #ifndef Grid_IMP #define Grid_IMP class Grid { Row *_rows[]; public: ~Grid() { int count = ArraySize(_rows); for (int i = 0; i < count; ++i) { delete _rows[i]; } } Row *AddRow() { int count = ArraySize(_rows); ArrayResize(_rows, count + 1); _rows[count] = new Row(); return _rows[count]; } Row *GetRow(const int index) { return _rows[index]; } void Draw() { int count = ArraySize(_rows); for (int i = 0; i < count; ++i) { _rows[i].Draw(); } } }; #endif // Trend value cell factory v2.0 // Interface for a cell factory v2.0 #ifndef ICellFactory_IMP #define ICellFactory_IMP class ICellFactory { public: virtual ICell* Create(const string id, const int x, const int y, ENUM_BASE_CORNER corner, const string symbol, const ENUM_TIMEFRAMES timeframe) = 0; virtual string GetHeader() = 0; }; #endif // Interface for a value formatter v1.0 #ifndef IValueFormatter_IMP #define IValueFormatter_IMP class IValueFormatter { public: virtual void AddRef() = 0; virtual void Release() = 0; virtual string FormatItem(const int period, const datetime date, color& textColor, color& bgColor) = 0; }; #endif //Signaler v 4.0 #ifdef ADVANCED_ALERTS // AdvancedNotificationsLib.dll could be downloaded here: http://profitrobots.com/Home/TelegramNotificationsMT4 #import "AdvancedNotificationsLib.dll" void AdvancedAlert(string key, string text, string instrument, string timeframe); #import #endif class Signaler { string _symbol; ENUM_TIMEFRAMES _timeframe; string _prefix; bool _popupAlert; bool _emailAlert; bool _playSound; string _soundFile; bool _notificationAlert; bool _advancedAlert; string _advancedKey; public: Signaler(const string symbol, ENUM_TIMEFRAMES timeframe) { _symbol = symbol; _timeframe = timeframe; _popupAlert = false; _emailAlert = false; _playSound = false; _notificationAlert = false; _advancedAlert = false; } void SetPopupAlert(bool isEnabled) { _popupAlert = isEnabled; } void SetEmailAlert(bool isEnabled) { _emailAlert = isEnabled; } void SetPlaySound(bool isEnabled, string fileName) { _playSound = isEnabled; _soundFile = fileName; } void SetNotificationAlert(bool isEnabled) { _notificationAlert = isEnabled; } void SetAdvancedAlert(bool isEnabled, string key) { _advancedAlert = isEnabled; _advancedKey = key; } void SendNotifications(string message, string subject = NULL, string symbol = NULL, string timeframe = NULL) { if (subject == NULL) subject = message; if (_prefix != "" && _prefix != NULL) message = _prefix + message; if (symbol == NULL) symbol = _symbol; if (timeframe == NULL) timeframe = GetTimeframeStr(); if (_popupAlert) Alert(message); if (_emailAlert) SendMail(subject, message); if (_playSound) PlaySound(_soundFile); if (_notificationAlert) SendNotification(message); #ifdef ADVANCED_ALERTS if (_advancedAlert && _advancedKey != "") AdvancedAlert(_advancedKey, message, symbol, timeframe); #endif } void SetMessagePrefix(string prefix) { _prefix = prefix; } string GetSymbol() { return _symbol; } ENUM_TIMEFRAMES GetTimeframe() { return _timeframe; } string GetTimeframeStr() { switch (_timeframe) { case PERIOD_M1: return "M1"; case PERIOD_M2: return "M2"; case PERIOD_M3: return "M3"; case PERIOD_M4: return "M4"; case PERIOD_M5: return "M5"; case PERIOD_M6: return "M6"; case PERIOD_M10: return "M10"; case PERIOD_M12: return "M12"; case PERIOD_M15: return "M15"; case PERIOD_M20: return "M20"; case PERIOD_M30: return "M30"; case PERIOD_D1: return "D1"; case PERIOD_H1: return "H1"; case PERIOD_H2: return "H2"; case PERIOD_H3: return "H3"; case PERIOD_H4: return "H4"; case PERIOD_H6: return "H6"; case PERIOD_H8: return "H8"; case PERIOD_H12: return "H12"; case PERIOD_MN1: return "MN1"; case PERIOD_W1: return "W1"; } return "M1"; } }; // Trend value cell v2.1 #ifndef TrendValueCell_IMP #define TrendValueCell_IMP #ifndef ENTER_BUY_SIGNAL #define ENTER_BUY_SIGNAL 1 #endif #ifndef ENTER_SELL_SIGNAL #define ENTER_SELL_SIGNAL -1 #endif enum OutputMode { OutputLabels, // Labels OutputButtonsNewWindow, // New chart buttons OutputButtons // Current chart buttons }; input OutputMode output_mode = OutputLabels; // Mode string TimeframeToString(ENUM_TIMEFRAMES timeframe) { switch (timeframe) { case PERIOD_M1: return "M1"; case PERIOD_M2: return "M2"; case PERIOD_M3: return "M3"; case PERIOD_M4: return "M4"; case PERIOD_M5: return "M5"; case PERIOD_M6: return "M6"; case PERIOD_M10: return "M10"; case PERIOD_M12: return "M12"; case PERIOD_M15: return "M15"; case PERIOD_M20: return "M20"; case PERIOD_M30: return "M30"; case PERIOD_D1: return "D1"; case PERIOD_H1: return "H1"; case PERIOD_H2: return "H2"; case PERIOD_H3: return "H3"; case PERIOD_H4: return "H4"; case PERIOD_H6: return "H6"; case PERIOD_H8: return "H8"; case PERIOD_H12: return "H12"; case PERIOD_MN1: return "MN1"; case PERIOD_W1: return "W1"; } return "M1"; } class TrendValueCell : public ICell { string _id; int _x; int _y; string _symbol; ENUM_TIMEFRAMES _timeframe; datetime _lastDatetime; ICondition* _conditions[]; IValueFormatter* _valueFormatters[]; IValueFormatter* _signalFormatters[]; IValueFormatter* _historyValueFormatters[]; Signaler* _signaler; datetime _lastSignalDate; int _lastSignal; int _alertShift; IValueFormatter* _defaultValue; bool _historicalMode; OutputMode _outputMode; ENUM_BASE_CORNER _corner; public: TrendValueCell(const string id, const int x, const int y, ENUM_BASE_CORNER __corner, const string symbol, const ENUM_TIMEFRAMES timeframe, int alertShift, IValueFormatter* defaultValue, OutputMode outputMode) { _corner = __corner; _outputMode = outputMode; _lastSignal = 0; _alertShift = alertShift; _signaler = new Signaler(symbol, timeframe); _signaler.SetMessagePrefix(symbol + "/" + TimeframeToString(timeframe) + ": "); _id = id; _x = x; _y = y; _symbol = symbol; _timeframe = timeframe; _defaultValue = defaultValue; _defaultValue.AddRef(); _historicalMode = true; } ~TrendValueCell() { delete _signaler; _defaultValue.Release(); for (int i = 0; i < ArraySize(_conditions); ++i) { _conditions[i].Release(); _valueFormatters[i].Release(); if (_signalFormatters[i] != NULL) { _signalFormatters[i].Release(); } if (_historyValueFormatters[i] != NULL) { _historyValueFormatters[i].Release(); } } ArrayResize(_conditions, 0); ArrayResize(_valueFormatters, 0); ArrayResize(_historyValueFormatters, 0); ArrayResize(_signalFormatters, 0); } void AddCondition(ICondition* condition, IValueFormatter* value, IValueFormatter* historyValue, IValueFormatter* signal) { int size = ArraySize(_conditions); ArrayResize(_conditions, size + 1); ArrayResize(_valueFormatters, size + 1); ArrayResize(_historyValueFormatters, size + 1); ArrayResize(_signalFormatters, size + 1); _conditions[size] = condition; condition.AddRef(); _valueFormatters[size] = value; value.AddRef(); _historyValueFormatters[size] = historyValue; if (historyValue != NULL) { historyValue.AddRef(); } else { _historicalMode = false; } _signalFormatters[size] = signal; if (signal != NULL) { signal.AddRef(); } } virtual void HandleButtonClicks() { for (int i = 0; i < ArraySize(_conditions); ++i) { string id = _id + "B"; if (ObjectGetInteger(0, id, OBJPROP_STATE)) { ObjectSetInteger(0, id, OBJPROP_STATE, false); if (_outputMode == OutputButtonsNewWindow) { ChartOpen(_symbol, _timeframe); } else { ChartSetSymbolPeriod(0, _symbol, _timeframe); } } } } virtual void Draw() { datetime date = iTime(_symbol, _timeframe, _alertShift); for (int i = 0; i < ArraySize(_conditions); ++i) { if (_conditions[i].IsPass(_alertShift, date)) { color textColor, bgColor; string text = _valueFormatters[i].FormatItem(_alertShift, date, textColor, bgColor); DrawItem(text, textColor, bgColor); if (_signalFormatters[i] != NULL) { text = _signalFormatters[i].FormatItem(_alertShift, date, textColor, bgColor); SendAlert(text, i); } return; } } if (_historicalMode) { DrawHistoricalValue(); return; } color textColor, bgColor; string text = _defaultValue.FormatItem(_alertShift, date, textColor, bgColor); DrawItem(text, textColor, bgColor); } private: void DrawHistoricalValue() { for (int period = _alertShift + 1; period < 1000; ++period) { datetime date = iTime(_symbol, _timeframe, period); for (int i = 0; i < ArraySize(_conditions); ++i) { if (_conditions[i].IsPass(period, date)) { color textColor, bgColor; string text = _historyValueFormatters[i].FormatItem(period, date, textColor, bgColor); DrawItem(text, textColor, bgColor); return; } } } } void DrawItem(string text, color textColor, color bgColor) { string id = _id + "B"; if (_outputMode == OutputLabels) { ObjectDelete(0, id); ObjectMakeLabel(id, _x, _y, text, textColor, _corner, ChartWindowFind(), "Arial", font_size); } else { ObjectDelete(0, id); if (ObjectFind(0, id) < 0) { ObjectCreate(0, id, OBJ_BUTTON, ChartWindowFind(), 0, 0); } ObjectSetInteger(0, id, OBJPROP_CORNER, _corner); ObjectSetInteger(0, id, OBJPROP_XDISTANCE, _x); ObjectSetInteger(0, id, OBJPROP_YDISTANCE, _y); ObjectSetString(0, id, OBJPROP_FONT, "Arial"); ObjectSetString(0, id, OBJPROP_TEXT, text); ObjectSetInteger(0, id, OBJPROP_COLOR, textColor); ObjectSetInteger(0, id, OBJPROP_BGCOLOR, bgColor); ObjectSetInteger(0, id, OBJPROP_FONTSIZE, font_size); TextSetFont("Arial", -font_size * 10); int width, height; TextGetSize(text, width, height); ObjectSetInteger(0, id, OBJPROP_XSIZE, MathMax(cell_width, width + 5)); ObjectSetInteger(0, id, OBJPROP_YSIZE, height + 5); } } void SendAlert(string text, int direction) { if (iTime(_symbol, _timeframe, 0) != _lastSignalDate && _lastSignal != direction) { _signaler.SendNotifications(text); _lastSignalDate = iTime(_symbol, _timeframe, 0); _lastSignal = direction; } } }; #endif // Abstrace value formatter v1.0 #ifndef AValueFormatter_IMP #define AValueFormatter_IMP class AValueFormatter : public IValueFormatter { int _references; public: AValueFormatter() { _references = 1; } virtual void AddRef() { ++_references; } virtual void Release() { --_references; if (_references == 0) delete &this; } }; #endif // Formats value as a contant/fixed text value v1.0 #ifndef FixedTextFormatter_IMP #define FixedTextFormatter_IMP class FixedTextFormatter : public AValueFormatter { string _text; color _clr; color _bgClr; public: FixedTextFormatter(string text, color clr, color bgClr) { _bgClr = bgClr; _text = text; _clr = clr; } virtual string FormatItem(const int period, const datetime date, color& clr, color& bgColor) { clr = _clr; bgColor = _bgClr; return _text; } }; #endif #ifndef TrendValueCellFactory_IMP #define TrendValueCellFactory_IMP class TrendValueCellFactory : public ICellFactory { int _alertShift; color _upColor; color _downColor; color _historicalUpColor; color _historicalDownColor; color _neutralColor; color _buttonTextColor; OutputMode _outputMode; public: TrendValueCellFactory(int alertShift = 0, color upColor = Green, color downColor = Red, color historicalUpColor = Lime, color historicalDownColor = Pink) { _outputMode = OutputLabels; _alertShift = alertShift; _upColor = upColor; _downColor = downColor; _historicalUpColor = historicalUpColor; _historicalDownColor = historicalDownColor; } void SetNeutralColor(color clr) { _neutralColor = clr; } void SetButtonTextColor(color clr) { _buttonTextColor = clr; } virtual string GetHeader() { return "Value"; } virtual ICell* Create(const string id, const int x, const int y, ENUM_BASE_CORNER __corner, const string symbol, const ENUM_TIMEFRAMES timeframe) { IValueFormatter* defaultValue = new FixedTextFormatter("-", GetTextColor(_neutralColor), GetBackgroundColor(_neutralColor)); TrendValueCell* cell = new TrendValueCell(id, x, y, __corner, symbol, timeframe, _alertShift, defaultValue, _outputMode); defaultValue.Release(); ICondition* upCondition = new UpCondition(symbol, timeframe); IValueFormatter* upValue = new FixedTextFormatter("Buy", GetTextColor(_upColor), GetBackgroundColor(_upColor)); IValueFormatter* historyUpValue = new FixedTextFormatter("Buy", GetTextColor(_historicalUpColor), GetBackgroundColor(_historicalUpColor)); cell.AddCondition(upCondition, upValue, historyUpValue, upValue); upCondition.Release(); upValue.Release(); historyUpValue.Release(); ICondition* downCondition = new DownCondition(symbol, timeframe); IValueFormatter* downValue = new FixedTextFormatter("Sell", GetTextColor(_downColor), GetBackgroundColor(_downColor)); IValueFormatter* historyDownValue = new FixedTextFormatter("Sell", GetTextColor(_historicalDownColor), GetBackgroundColor(_historicalDownColor)); cell.AddCondition(downCondition, downValue, historyDownValue, downValue); downCondition.Release(); downValue.Release(); historyDownValue.Release(); return cell; } private: color GetTextColor(color clr) { return _outputMode == OutputLabels ? clr : _buttonTextColor; } color GetBackgroundColor(color clr) { return _outputMode != OutputLabels ? clr : _buttonTextColor; } }; #endif Grid *grid; // Grid builder v2.0 #ifndef GridBuilder_IMP #define GridBuilder_IMP class GridBuilder { string _symbols[]; int _symbolsCount; Grid *grid; int _originalX; int _originalY; Iterator _xIterator; Iterator _yIterator; bool _verticalMode; int _cellHeight; int _headerHeight; ICellFactory* _cellFactory[]; ENUM_BASE_CORNER _corner; public: GridBuilder(int x, int y, int headerHeight, int cellHeight, bool verticalMode, ENUM_BASE_CORNER __corner) :_xIterator(x, -cell_width), _yIterator(y, cellHeight) { _corner = __corner; _cellHeight = cellHeight; _headerHeight = headerHeight; _verticalMode = verticalMode; _originalY = y; _originalX = x; grid = new Grid(); } ~GridBuilder() { for (int i = 0; i < ArraySize(_cellFactory); ++i) { delete _cellFactory[i]; } ArrayResize(_cellFactory, 0); } void AddCell(ICellFactory* cellFactory) { int size = ArraySize(_cellFactory); ArrayResize(_cellFactory, size + 1); _cellFactory[size] = cellFactory; } void SetSymbols(const string symbols) { StringSplit(symbols, ',', _symbols); _symbolsCount = ArraySize(_symbols); int cellFactorySize = ArraySize(_cellFactory); if (_verticalMode) { Iterator yIterator(_originalY, _cellHeight); if (cellFactorySize > 1) { yIterator.GetNext(); } Row* row = grid.AddRow(); row.Add(new EmptyCell()); for (int i = 0; i < _symbolsCount; i++) { string id = IndicatorObjPrefix + _symbols[i] + "_Name"; row.Add(new LabelCell(id, _symbols[i], _originalX + cell_width, yIterator.GetNext(), _corner)); } } else { //TODO: add support of multiple values Iterator xIterator(_originalX - cell_width, -cell_width); Row* row = grid.AddRow(); row.Add(new EmptyCell()); for (int i = 0; i < _symbolsCount; i++) { string id = IndicatorObjPrefix + _symbols[i] + "_Name"; row.Add(new LabelCell(id, _symbols[i], xIterator.GetNext(), _originalY - _headerHeight, _corner)); } } } void AddTimeframe(const string label, const ENUM_TIMEFRAMES timeframe) { int cellFactorySize = ArraySize(_cellFactory); if (_verticalMode) { int x[]; ArrayResize(x, cellFactorySize); for (int ii = 0; ii < cellFactorySize; ++ii) { x[ii] = _xIterator.GetNext(); } Row* column[]; ArrayResize(column, cellFactorySize); for (int ii = 0; ii < cellFactorySize; ++ii) { column[ii] = grid.AddRow(); #ifndef EXCLUDE_PERIOD_HEADER if (ii > 0) { column[ii].Add(new EmptyCell()); } else { column[ii].Add(new LabelCell(IndicatorObjPrefix + label + "_h", label, x[0], _headerHeight, _corner)); } #endif } Iterator yIterator(_originalY, _cellHeight); if (cellFactorySize > 1) { int y = yIterator.GetNext(); for (int ii = 0; ii < cellFactorySize; ++ii) { string index = IntegerToString(ii + 1); column[ii].Add(new LabelCell(IndicatorObjPrefix + label + "_sh" + index, _cellFactory[ii].GetHeader(), x[ii], y, _corner)); } } for (int i = 0; i < _symbolsCount; i++) { int y = yIterator.GetNext(); for (int ii = 0; ii < cellFactorySize; ++ii) { string id = IndicatorObjPrefix + _symbols[i] + "_" + label + IntegerToString(ii); column[ii].Add(_cellFactory[ii].Create(id, x[ii], y, _corner, _symbols[i], timeframe)); } } } else { //TODO: add support of multiple values int y[]; ArrayResize(y, cellFactorySize); for (int ii = 0; ii < cellFactorySize; ++ii) { y[ii] = _yIterator.GetNext(); } Row* row = grid.AddRow(); #ifndef EXCLUDE_PERIOD_HEADER row.Add(new LabelCell(IndicatorObjPrefix + label + "_Label", label, _originalX, y[0], _corner)); #endif Iterator xIterator(_originalX - cell_width, -cell_width); for (int i = 0; i < _symbolsCount; i++) { string id = IndicatorObjPrefix + _symbols[i] + "_" + label; int x = xIterator.GetNext(); for (int ii = 0; ii < cellFactorySize; ++ii) { row.Add(_cellFactory[ii].Create(id, x, y[ii], _corner, _symbols[i], timeframe)); } } } } Grid* Build() { return grid; } }; #endif string IndicatorName; string IndicatorObjPrefix; bool NamesCollision(const string name) { for (int k = ObjectsTotal(0); k >= 0; k--) { if (StringFind(ObjectName(0, k), name) == 0) { return true; } } return false; } string GenerateIndicatorPrefix(const string target) { for (int i = 0; i < 1000; ++i) { string prefix = target + "_" + IntegerToString(i); if (!NamesCollision(prefix)) { return prefix; } } return target; } int OnInit(void) { IndicatorObjPrefix = GenerateIndicatorPrefix("..."); IndicatorSetString(INDICATOR_SHORTNAME, "..."); IndicatorSetInteger(INDICATOR_DIGITS, Digits()); GridBuilder builder(x_shift, 50, cell_height, cell_height, display_mode == Vertical, corner); TrendValueCellFactory* factory = new TrendValueCellFactory(alert_on_close ? 1 : 0, Up_Color, Dn_Color, historical_Up_Color, historical_Dn_Color); factory.SetNeutralColor(neutral_color); factory.SetButtonTextColor(button_text_color); builder.AddCell(factory); builder.SetSymbols(Pairs); if (Include_M1) builder.AddTimeframe("M1", PERIOD_M1); if (Include_M5) builder.AddTimeframe("M5", PERIOD_M5); if (Include_M15) builder.AddTimeframe("M15", PERIOD_M15); if (Include_M30) builder.AddTimeframe("M30", PERIOD_M30); if (Include_H1) builder.AddTimeframe("H1", PERIOD_H1); if (Include_H4) builder.AddTimeframe("H4", PERIOD_H4); if (Include_D1) builder.AddTimeframe("D1", PERIOD_D1); if (Include_W1) builder.AddTimeframe("W1", PERIOD_W1); if (Include_MN1) builder.AddTimeframe("MN1", PERIOD_MN1); grid = builder.Build(); return(0); } void OnDeinit(const int reason) { ObjectsDeleteAll(ChartID(), IndicatorObjPrefix); delete grid; grid = NULL; } 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[]) { grid.Draw(); return 0; }