//+------------------------------------------------------------------+ //| EA31337 framework | //| Copyright 2016-2023, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ /* * This file is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /** * @file * Includes Bar's structs. */ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once #endif // Forward class declaration. class Serializer; // Includes. #include "Bar.enum.h" #include "Chart.enum.h" #include "ISerializable.h" #include "Serializer.enum.h" #include "SerializerNode.enum.h" #include "Std.h" /* Structure for storing OHLC values. */ template struct CandleOHLC #ifndef __MQL__ : public ISerializable #endif { T open, high, low, close; // Struct constructors. CandleOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0) : open(_open), high(_high), low(_low), close(_close) {} CandleOHLC(ARRAY_REF(T, _prices)) { int _size = ArraySize(_prices); close = _prices[0]; open = _prices[_size - 1]; high = fmax(close, open); low = fmin(close, open); for (int i = 0; i < _size; i++) { high = fmax(high, _prices[i]); low = fmin(low, _prices[i]); } } // Struct methods. // Getters bool GetPivots(ENUM_PP_TYPE _type, T &_pp, T &_r1, T &_r2, T &_r3, T &_r4, T &_s1, T &_s2, T &_s3, T &_s4) { T _range = GetRange(); switch (_type) { case PP_CAMARILLA: // A set of eight very probable levels which resemble support and resistance values for a current trend. _pp = GetPivot(); _r1 = (T)(close + _range * 1.1 / 12); _r2 = (T)(close + _range * 1.1 / 6); _r3 = (T)(close + _range * 1.1 / 4); _r4 = (T)(close + _range * 1.1 / 2); _s1 = (T)(close - _range * 1.1 / 12); _s2 = (T)(close - _range * 1.1 / 6); _s3 = (T)(close - _range * 1.1 / 4); _s4 = (T)(close - _range * 1.1 / 2); break; case PP_CLASSIC: _pp = GetPivot(); _r1 = (2 * _pp) - low; // R1 = (H - L) * 1.1 / 12 + C (1.0833) _r2 = _pp + _range; // R2 = (H - L) * 1.1 / 6 + C (1.1666) _r3 = _pp + _range * 2; // R3 = (H - L) * 1.1 / 4 + C (1.25) _r4 = _pp + _range * 3; // R4 = (H - L) * 1.1 / 2 + C (1.5) _s1 = (2 * _pp) - high; // S1 = C - (H - L) * 1.1 / 12 (1.0833) _s2 = _pp - _range; // S2 = C - (H - L) * 1.1 / 6 (1.1666) _s3 = _pp - _range * 2; // S3 = C - (H - L) * 1.1 / 4 (1.25) _s4 = _pp - _range * 3; // S4 = C - (H - L) * 1.1 / 2 (1.5) break; case PP_FIBONACCI: _pp = GetPivot(); _r1 = (float)(_pp + 0.382 * _range); _r2 = (float)(_pp + 0.618 * _range); _r3 = _pp + _range; _r4 = _r1 + _range; // ? _s1 = (float)(_pp - 0.382 * _range); _s2 = (float)(_pp - 0.618 * _range); _s3 = _pp - _range; _s4 = _s1 - _range; // ? break; case PP_FLOOR: // Most basic and popular type of pivots used in Forex trading technical analysis. _pp = GetPivot(); // Pivot (P) = (H + L + C) / 3 _r1 = (2 * _pp) - low; // Resistance (R1) = (2 * P) - L _r2 = _pp + _range; // R2 = P + H - L _r3 = high + 2 * (_pp - low); // R3 = H + 2 * (P - L) _r4 = _r3; _s1 = (2 * _pp) - high; // Support (S1) = (2 * P) - H _s2 = _pp - _range; // S2 = P - H + L _s3 = low - 2 * (high - _pp); // S3 = L - 2 * (H - P) _s4 = _s3; // ? break; case PP_TOM_DEMARK: // Tom DeMark's pivot point (predicted lows and highs of the period). _pp = GetPivotDeMark(); _r1 = (2 * _pp) - low; // New High = X / 2 - L. _r2 = _pp + _range; _r3 = _r1 + _range; _r4 = _r2 + _range; // ? _s1 = (2 * _pp) - high; // New Low = X / 2 - H. _s2 = _pp - _range; _s3 = _s1 - _range; _s4 = _s2 - _range; // ? break; case PP_WOODIE: // Woodie's pivot point are giving more weight to the Close price of the previous period. // They are similar to floor pivot points, but are calculated in a somewhat different way. _pp = GetWeighted(); // Pivot (P) = (H + L + 2 * C) / 4 _r1 = (2 * _pp) - low; // Resistance (R1) = (2 * P) - L _r2 = _pp + _range; // R2 = P + H - L _r3 = _r1 + _range; _r4 = _r2 + _range; // ? _s1 = (2 * _pp) - high; // Support (S1) = (2 * P) - H _s2 = _pp - _range; // S2 = P - H + L _s3 = _s1 - _range; _s4 = _s2 - _range; // ? break; default: break; } return _r4 > _r3 && _r3 > _r2 && _r2 > _r1 && _r1 > _pp && _pp > _s1 && _s1 > _s2 && _s2 > _s3 && _s3 > _s4; } T GetAppliedPrice(ENUM_APPLIED_PRICE _ap) const { return CandleOHLC::GetAppliedPrice(_ap, open, high, low, close); } T GetBody() const { return close - open; } T GetBodyAbs() const { return fabs(close - open); } T GetBodyInPct(int _hundreds = 100) const { return GetRange() > 0 ? _hundreds / GetRange() * GetBodyAbs() : 0; } T GetChangeInPct(int _hundreds = 100) const { return (close - open) / open * _hundreds; } T GetClose() const { return close; } T GetHigh() const { return high; } T GetLow() const { return low; } T GetMaxOC() const { return fmax(open, close); } T GetMedian() const { return (high + low) / 2; } T GetMinOC() const { return fmin(open, close); } T GetOpen() const { return open; } T GetPivot() const { return GetTypical(); } T GetPivotDeMark() const { // If Close < Open Then X = H + 2 * L + C // If Close > Open Then X = 2 * H + L + C // If Close = Open Then X = H + L + 2 * C T _pp = open > close ? (high + (2 * low) + close) / 4 : ((2 * high) + low + close) / 4; return open == close ? (high + low + (2 * close)) / 4 : _pp; } T GetPivotWithOpen() const { return (open + high + low + close) / 4; } T GetPivotWithOpen(float _open) const { return (_open + high + low + close) / 4; } T GetRange() const { return high - low; } T GetRangeChangeInPct(int _hundreds = 100) const { return _hundreds - (_hundreds / open * fabs(open - GetRange())); } T GetRangeInPips(float _ppp) const { return GetRange() / _ppp; } T GetTypical() const { return (high + low + close) / 3; } T GetWeighted() const { return (high + low + close + close) / 4; } T GetWickMin() const { return fmin(GetWickLower(), GetWickUpper()); } T GetWickLower() const { return GetMinOC() - low; } T GetWickLowerInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickLower() : 0; } T GetWickMax() const { return fmax(GetWickLower(), GetWickUpper()); } T GetWickSum() const { return GetWickLower() + GetWickUpper(); } T GetWickUpper() const { return high - GetMaxOC(); } T GetWickUpperInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickUpper() : 0; } short GetType() const { return IsBull() ? 1 : (IsBear() ? -1 : 0); } void GetValues(ARRAY_REF(T, _out)) { ArrayResize(_out, 4); int _index = ArraySize(_out) - 4; _out[_index++] = open; _out[_index++] = high; _out[_index++] = low; _out[_index++] = close; } static T GetAppliedPrice(ENUM_APPLIED_PRICE _ap, T _o, T _h, T _l, T _c) { switch (_ap) { case PRICE_CLOSE: return _c; case PRICE_OPEN: return _o; case PRICE_HIGH: return _h; case PRICE_LOW: return _l; case PRICE_MEDIAN: return (_h + _l) / 2; case PRICE_TYPICAL: return (_h + _l + _c) / 3; case PRICE_WEIGHTED: return (_h + _l + _c + _c) / 4; default: return _o; } } // State checkers. bool IsBear() const { return open > close; } bool IsBull() const { return open < close; } bool IsValid() const { return high >= low && fmin(open, close) > 0; } // Serializers. SerializerNodeType Serialize(Serializer &s); // Converters. string ToCSV() { return StringFormat("%g,%g,%g,%g", open, high, low, close); } }; /* Structure for storing OHLC values with open and close timestamp. */ template struct CandleOCTOHLC : CandleOHLC { long open_timestamp, close_timestamp; // Struct constructors. CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, long _open_timestamp = -1, long _close_timestamp = -1) : CandleOHLC(_open, _high, _low, _close), open_timestamp(_open_timestamp), close_timestamp(_close_timestamp) {} // Updates OHLC values taking into consideration tick's timestamp. void Update(long _timestamp, T _price) { if (_timestamp < open_timestamp) { open_timestamp = _timestamp; open = _price; } if (_timestamp > close_timestamp) { close_timestamp = _timestamp; close = _price; } high = MathMax(high, _price); low = MathMin(low, _price); } // Returns timestamp of open price. long GetOpenTimestamp() { return open_timestamp; } // Returns timestamp of close price. long GetCloseTimestamp() { return close_timestamp; } }; /* Structore for storing OHLC values with timestamp. */ template struct CandleTOHLC : CandleOHLC { datetime time; // Struct constructors. CandleTOHLC(datetime _time = 0, T _open = 0, T _high = 0, T _low = 0, T _close = 0) : time(_time), CandleOHLC(_open, _high, _low, _close) {} // Getters. datetime GetTime() { return time; } // Serializers. SerializerNodeType Serialize(Serializer &s); // Converters. string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); } }; #include "Serializer.mqh" /* Method to serialize CandleEntry structure. */ template SerializerNodeType CandleOHLC::Serialize(Serializer &s) { // s.Pass(THIS_REF, "time", TimeToString(time)); s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } /* Method to serialize CandleEntry structure. */ template SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { s.Pass(THIS_REF, "time", time); s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; }