// More information about this indicator can be found at: // http://fxcodebase.com/ //+------------------------------------------------------------------+ //| Copyright © 2020, Gehtsoft USA LLC | //| http://fxcodebase.com | //+------------------------------------------------------------------+ //| Developed by : Mario Jemic | //| mario.jemic@gmail.com | //+------------------------------------------------------------------+ //| Support our efforts by donating | //| Paypal: https://goo.gl/9Rj74e | //+------------------------------------------------------------------+ //| Patreon : https://goo.gl/GdXWeN | //| BitCoin : 15VCJTLaz12Amr7adHSBtL9v8XomURo9RF | //| BitCoin Cash: 1BEtS465S3Su438Kc58h2sqvVvHK9Mijtg | //| Ethereum : 0x8C110cD61538fb6d7A2B47858F0c0AaBd663068D | //| LiteCoin : LLU8PSY2vsq7B9kRELLZQcKf5nJQrdeqwD | //+------------------------------------------------------------------+ #property indicator_chart_window #property strict #property indicator_plots 0 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; input color Up_Color = clrLime; input color Dn_Color = clrRed; input color Neutral_Color = clrDarkGray; input int x_shift = 50; // X coordinate 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 #define MAX_LOOPBACK 500 string WindowName; // Base condition v1.0 #ifndef ABaseCondition_IMP #define ABaseCondition_IMP // Condition base v1.0 #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; }; #endif class AConditionBase : public ICondition { int _references; public: AConditionBase() { _references = 1; } virtual void AddRef() { ++_references; } virtual void Release() { --_references; if (_references == 0) delete &this; } }; #endif // Symbol info v.1.2 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); } 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; } double GetBid() { return SymbolInfoDouble(_symbol, SYMBOL_BID); } double GetAsk() { return SymbolInfoDouble(_symbol, SYMBOL_ASK); } double GetMinVolume() { return SymbolInfoDouble(_symbol, SYMBOL_VOLUME_MIN); } double RoundRate(const double rate) { return NormalizeDouble(MathRound(rate / _ticksize) * _ticksize, _digit); } }; class ACondition : public AConditionBase { protected: ENUM_TIMEFRAMES _timeframe; InstrumentInfo* _instrument; string _symbol; public: ACondition(const string symbol, ENUM_TIMEFRAMES timeframe) { _instrument = new InstrumentInfo(symbol); _timeframe = timeframe; _symbol = symbol; } ~ACondition() { delete _instrument; } }; #endif class UpCondition : public ACondition { public: UpCondition(const string symbol, ENUM_TIMEFRAMES timeframe) :ACondition(symbol, timeframe) { } virtual bool IsPass(const int period, const datetime date) { return iOpen(_symbol, _timeframe, 0) < iClose(_symbol, _timeframe, 0); } }; class DownCondition : public ACondition { public: DownCondition(const string symbol, ENUM_TIMEFRAMES timeframe) :ACondition(symbol, timeframe) { } virtual bool IsPass(const int period, const datetime date) { return iOpen(_symbol, _timeframe, 0) > iClose(_symbol, _timeframe, 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 v1.0 #ifndef LabelCell_IMP #define LabelCell_IMP class LabelCell : public ICell { string _id; string _text; int _x; int _y; public: LabelCell(const string id, const string text, const int x, const int y) { _id = id; _text = text; _x = x; _y = y; } virtual void Draw() { ObjectMakeLabel(_id, _x, _y, _text, Labels_Color, 1, 0, "Arial", font_size); } }; #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 v1.0 // Interface for a cell factory v1.0 #ifndef ICellFactory_IMP #define ICellFactory_IMP class ICellFactory { public: virtual ICell* Create(const string id, const int x, const int y, const string symbol, const ENUM_TIMEFRAMES timeframe) = 0; }; #endif // Trend value cell v1.0 #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 class TrendValueCell : public ICell { string _id; int _x; int _y; string _symbol; ENUM_TIMEFRAMES _timeframe; datetime _lastDatetime; ICondition* _upCondition; ICondition* _downCondition; datetime _lastSignalDate; public: TrendValueCell(const string id, const int x, const int y, const string symbol, const ENUM_TIMEFRAMES timeframe) { _id = id; _x = x; _y = y; _symbol = symbol; _timeframe = timeframe; _upCondition = CreateUpCondition(_symbol, _timeframe); _downCondition = CreateDownCondition(_symbol, _timeframe); } ~TrendValueCell() { delete _upCondition; delete _downCondition; } virtual void Draw() { int direction = GetDirection(); ObjectMakeLabel(_id, _x, _y, GetDirectionSymbol(direction), GetDirectionColor(direction), 1, 0, "Arial", font_size); datetime currentTime = iTime(_symbol, _timeframe, 0); if (currentTime != _lastSignalDate) { switch (direction) { case ENTER_BUY_SIGNAL: _lastSignalDate = currentTime; break; case ENTER_SELL_SIGNAL: _lastSignalDate = currentTime; break; } } } private: int GetDirection() { datetime date = iTime(_symbol, _timeframe, 0); if (_upCondition.IsPass(0, date)) return ENTER_BUY_SIGNAL; if (_downCondition.IsPass(0, date)) return ENTER_SELL_SIGNAL; return 0; } color GetDirectionColor(const int direction) { if (direction >= 1) { return Up_Color; } else if (direction <= -1) { return Dn_Color; } return Neutral_Color; } string GetDirectionSymbol(const int direction) { if (direction == ENTER_BUY_SIGNAL) return "UP"; else if (direction == ENTER_SELL_SIGNAL) return "DOWN"; return "-"; } }; #endif #ifndef TrendValueCellFactory_IMP #define TrendValueCellFactory_IMP class TrendValueCellFactory : public ICellFactory { public: virtual ICell* Create(const string id, const int x, const int y, const string symbol, const ENUM_TIMEFRAMES timeframe) { return new TrendValueCell(id, x, y, symbol, timeframe); } }; #endif Grid *grid; // Grid builder v1.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; public: GridBuilder(int x, int y, int headerHeight, int cellHeight, bool verticalMode, ICellFactory* cellFactory) :_xIterator(x, cell_width), _yIterator(y, cellHeight) { _cellHeight = cellHeight; _headerHeight = headerHeight; _cellFactory = cellFactory; _verticalMode = verticalMode; _originalY = y; _originalX = x; grid = new Grid(); } ~GridBuilder() { delete _cellFactory; } void SetSymbols(const string symbols) { split(_symbols, symbols, ","); _symbolsCount = ArraySize(_symbols); if (_verticalMode) { int x = _xIterator.GetNext(); Iterator yIterator(_originalY, _cellHeight); 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], x, yIterator.GetNext())); } } else { 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)); } } } void AddTimeframe(const string label, const ENUM_TIMEFRAMES timeframe) { if (_verticalMode) { int x = _xIterator.GetNext(); Row *row = grid.AddRow(); row.Add(new LabelCell(IndicatorObjPrefix + label + "_Label", label, x, _headerHeight)); Iterator yIterator(_originalY, _cellHeight); for (int i = 0; i < _symbolsCount; i++) { string id = IndicatorObjPrefix + _symbols[i] + "_" + label; row.Add(_cellFactory.Create(id, x, yIterator.GetNext(), _symbols[i], timeframe)); } } else { int y = _yIterator.GetNext(); Row *row = grid.AddRow(); row.Add(new LabelCell(IndicatorObjPrefix + label + "_Label", label, _originalX, y)); Iterator xIterator(_originalX + cell_width, cell_width); for (int i = 0; i < _symbolsCount; i++) { string id = IndicatorObjPrefix + _symbols[i] + "_" + label; row.Add(_cellFactory.Create(id, xIterator.GetNext(), y, _symbols[i], timeframe)); } } } Grid* Build() { return grid; } private: void split(string& arr[], string str, string sym) { ArrayResize(arr, 0); int len = StringLen(str); for (int i=0; i < len;) { int pos = StringFind(str, sym, i); if (pos == -1) pos = len; string item = StringSubstr(str, i, pos-i); StringTrimLeft(item); StringTrimRight(item); int size = ArraySize(arr); ArrayResize(arr, size+1); arr[size] = item; i = pos+1; } } }; #endif string IndicatorName; string IndicatorObjPrefix; string GenerateIndicatorName(const string target) { string name = target; return name; } int OnInit(void) { IndicatorName = GenerateIndicatorName("Trend indicator_LuXingMod_AUD"); IndicatorObjPrefix = "__" + IndicatorName + "__"; IndicatorSetString(INDICATOR_SHORTNAME, IndicatorName); IndicatorSetInteger(INDICATOR_DIGITS, Digits()); GridBuilder builder(x_shift, 50, cell_height, cell_height, display_mode == Vertical, new TrendValueCellFactory()); 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; }