Skip to content

Commit

Permalink
Added Indi_AppliedPrice indicator and fixed some of the "delete inval…
Browse files Browse the repository at this point in the history
…id pointer" errors.
  • Loading branch information
nseam committed Aug 5, 2021
1 parent e19b969 commit 8ac67d3
Show file tree
Hide file tree
Showing 12 changed files with 399 additions and 159 deletions.
51 changes: 30 additions & 21 deletions EA.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ class EA {
Account *account;
DictObject<ENUM_TIMEFRAMES, DictStruct<long, Ref<Strategy>>> strats;
DictStruct<short, TaskEntry> tasks;
Market *market;
Ref<Market> market;
Ref<Log> logger;
SummaryReport *report;
Terminal *terminal;
Ref<Terminal> terminal;

// Data variables.
BufferStruct<ChartEntry> data_chart;
Expand Down Expand Up @@ -102,9 +102,7 @@ class EA {
ProcessTasks();
// Deinitialize classes.
Object::Delete(account);
Object::Delete(market);
Object::Delete(report);
Object::Delete(terminal);
}

Log *Logger() { return logger.Ptr(); }
Expand Down Expand Up @@ -274,12 +272,12 @@ class EA {
if (estate.IsEnabled()) {
eresults.Reset();
if (estate.IsActive()) {
market.SetTick(SymbolInfoStatic::GetTick(_Symbol));
GetMarket().SetTick(SymbolInfoStatic::GetTick(_Symbol));
ProcessPeriods();
for (DictObjectIterator<ENUM_TIMEFRAMES, DictStruct<long, Ref<Strategy>>> iter_tf = strats.Begin();
iter_tf.IsValid(); ++iter_tf) {
ENUM_TIMEFRAMES _tf = iter_tf.Key();
ProcessTickByTf(_tf, market.GetLastTick());
ProcessTickByTf(_tf, GetMarket().GetLastTick());
}
if (eresults.last_error > ERR_NO_ERROR) {
logger.Ptr().Flush();
Expand Down Expand Up @@ -624,12 +622,12 @@ class EA {
* Update EA state flags.
*/
void UpdateStateFlags() {
estate.SetFlag(EA_STATE_FLAG_CONNECTED, terminal.IsConnected());
estate.SetFlag(EA_STATE_FLAG_LIBS_ALLOWED, terminal.IsLibrariesAllowed());
estate.SetFlag(EA_STATE_FLAG_OPTIMIZATION, terminal.IsOptimization());
estate.SetFlag(EA_STATE_FLAG_TESTING, terminal.IsTesting());
estate.SetFlag(EA_STATE_FLAG_TRADE_ALLOWED, terminal.IsTradeAllowed());
estate.SetFlag(EA_STATE_FLAG_VISUAL_MODE, terminal.IsVisualMode());
estate.SetFlag(EA_STATE_FLAG_CONNECTED, GetTerminal().IsConnected());
estate.SetFlag(EA_STATE_FLAG_LIBS_ALLOWED, GetTerminal().IsLibrariesAllowed());
estate.SetFlag(EA_STATE_FLAG_OPTIMIZATION, GetTerminal().IsOptimization());
estate.SetFlag(EA_STATE_FLAG_TESTING, GetTerminal().IsTesting());
estate.SetFlag(EA_STATE_FLAG_TRADE_ALLOWED, GetTerminal().IsTradeAllowed());
estate.SetFlag(EA_STATE_FLAG_VISUAL_MODE, GetTerminal().IsVisualMode());
}

/**
Expand Down Expand Up @@ -676,7 +674,7 @@ class EA {
case EA_COND_IS_ENABLED:
return estate.IsEnabled();
case EA_COND_IS_NOT_CONNECTED:
estate.SetFlag(EA_STATE_FLAG_CONNECTED, terminal.IsConnected());
estate.SetFlag(EA_STATE_FLAG_CONNECTED, GetTerminal().IsConnected());
return !estate.IsConnected();
case EA_COND_ON_NEW_MINUTE: // On new minute.
return (estate.new_periods & DATETIME_MINUTE) != 0;
Expand Down Expand Up @@ -775,6 +773,16 @@ class EA {

/* Getters */

/**
* Returns pointer to Terminal object.
*/
Market *GetMarket() { return market.Ptr(); }

/**
* Returns pointer to Market object.
*/
Terminal *GetTerminal() { return terminal.Ptr(); }

/**
* Gets EA's name.
*/
Expand Down Expand Up @@ -843,7 +851,7 @@ class EA {
/**
* Gets pointer to market details.
*/
Market *Market() { return market; }
Market *Market() { return market.Ptr(); }

/**
* Gets pointer to strategies.
Expand All @@ -853,12 +861,7 @@ class EA {
/**
* Gets pointer to symbol details.
*/
SymbolInfo *SymbolInfo() { return (SymbolInfo *)market; }

/**
* Gets pointer to terminal instance.
*/
Terminal *Terminal() { return terminal; }
SymbolInfo *SymbolInfo() { return (SymbolInfo *)GetMarket(); }

/* Setters */

Expand Down Expand Up @@ -920,7 +923,13 @@ class EA {
*/
SerializerNodeType Serialize(Serializer &_s) {
_s.Pass(THIS_REF, "account", account, SERIALIZER_FIELD_FLAG_DYNAMIC);
_s.Pass(THIS_REF, "market", market, SERIALIZER_FIELD_FLAG_DYNAMIC);

// In MQL it will be: Market* _market = GetMarket();
// In C++ it will be: Market& _market = GetMarket();
// It is needed as PassObject() expects reference to object instead of its pointer.
MAKE_REF_FROM_PTR(Market, _market, GetMarket());
_s.PassObject(THIS_REF, "market", _market, SERIALIZER_FIELD_FLAG_DYNAMIC);

for (DictObjectIterator<ENUM_TIMEFRAMES, DictStruct<long, Ref<Strategy>>> _iter_tf = GetStrategies().Begin();
_iter_tf.IsValid(); ++_iter_tf) {
ENUM_TIMEFRAMES _tf = _iter_tf.Key();
Expand Down
1 change: 1 addition & 0 deletions Indicator.enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ enum ENUM_INDICATOR_TYPE {
INDI_ADXW, // ADX by Welles Wilder
INDI_ALLIGATOR, // Alligator
INDI_AMA, // Adaptive Moving Average
INDI_APPLIED_PRICE, // Applied Price over OHLC Indicator
INDI_AO, // Awesome Oscillator
INDI_ASI, // Accumulation Swing Index
INDI_ATR, // Average True Range
Expand Down
23 changes: 23 additions & 0 deletions Indicator.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ class Indicator : public Chart {

if (iparams.indi_data_source != NULL && iparams.indi_managed) {
// User selected custom, managed data source.
if (CheckPointer(iparams.indi_data_source) == POINTER_INVALID) {
DebugBreak();
}
delete iparams.indi_data_source;
iparams.indi_data_source = NULL;
}
Expand Down Expand Up @@ -444,6 +447,26 @@ class Indicator : public Chart {
}
}

/**
* Checks whether indicator have given mode index.
*
* If given mode is -1 (default one) and indicator has exactly one mode, then mode index will be replaced by 0.
*/
void ValidateDataSourceMode(int& _out_mode) {
if (_out_mode == -1) {
// First mode will be used by default, or, if selected indicator has more than one mode, error will happen.
if (iparams.max_modes != 1) {
Alert("Error: ", GetName(), " must have exactly one possible mode in order to skip using SetDataSourceMode()!");
DebugBreak();
}
_out_mode = 0;
} else if (_out_mode + 1 > (int)iparams.max_modes) {
Alert("Error: ", GetName(), " have ", iparams.max_modes, " mode(s) buy you tried to reference mode with index ",
_out_mode, "! Ensure that you properly set mode via SetDataSourceMode().");
DebugBreak();
}
}

/**
* Provides built-in indicators whose can be used as data source.
*/
Expand Down
160 changes: 160 additions & 0 deletions Indicators/Indi_AppliedPrice.mqh
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
//+------------------------------------------------------------------+
//| EA31337 framework |
//| Copyright 2016-2021, 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 <http://www.gnu.org/licenses/>.
*
*/

// Includes.
#include "../BufferStruct.mqh"
#include "../Indicator.mqh"

// Structs.
struct AppliedPriceParams : IndicatorParams {
unsigned int smooth_period;
unsigned int chv_period;
ENUM_MA_METHOD smooth_method;
// Struct constructor.
void CHVParams(int _mode) {
chv_period = _chv_period;
itype = INDI_APPLIED_PRICE;
max_modes = 1;
SetDataValueType(TYPE_DOUBLE);
SetDataValueRange(IDATA_RANGE_PRICE);
SetDataSourceType(IDATA_ICUSTOM);
};
void CHVParams(CHVParams &_params) { this = _params; };
};

/**
* Implements the "Applied Price over OHCL Indicator" indicator, e.g. over Indi_Price.
*/
class Indi_AppliedPrice : public Indicator {
protected:
AppliedPrice params;

public:
/**
* Class constructor.
*/
Indi_AppliedPrice(AppliedPriceParams &_params) : params(_params){};
Indi_AppliedPrice() : Indicator(INDI_APPLIED_PRICE){};

static double iCCIOnIndicator(Indicator *_indi, int _applied_price, int _shift = 0) {
double _ohlc[4];
_indi.GetArray(_ohlc, 4);
return BarOHLC::GetAppliedPrice(_applied_price, _ohlc[0], _ohlc[1], _ohlc[2], _ohlc[3]);
}

/**
* Returns the indicator's value.
*/
double GetValue(int _shift = 0) {
ResetLastError();
double _value = EMPTY_VALUE;
switch (params.idstype) {
case IDATA_ICUSTOM:
if (GetDataSourceMode() == -1) {
Print(
"Please use SetDataSourceMode() to select source indicator's buffer. Note that SetAppliedPrice() can be "
"used only with built-in or compiled indicators, but not with indicator-on-indicator mode.");
DebugBreak();
}
_value = Indi_AppliedPrice::iAppliedPriceOnIndicator(GetDataSource(), GetDataSourceMode(), _shift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
}
istate.is_ready = _LastError == ERR_NO_ERROR;
istate.is_changed = false;
return _value;
}

/**
* Returns the indicator's struct value.
*/
IndicatorDataEntry GetEntry(int _shift = 0) {
long _bar_time = GetBarTime(_shift);
unsigned int _position;
IndicatorDataEntry _entry(params.max_modes);
if (idata.KeyExists(_bar_time, _position)) {
_entry = idata.GetByPos(_position);
} else {
_entry.timestamp = GetBarTime(_shift);
_entry.values[0] = GetValue(_shift);
_entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue<double>(NULL) && !_entry.HasValue<double>(EMPTY_VALUE));
if (_entry.IsValid()) {
_entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType()));
idata.Add(_entry, _bar_time);
}
}
return _entry;
}

/**
* Returns the indicator's entry value.
*/
MqlParam GetEntryValue(int _shift = 0, int _mode = 0) {
MqlParam _param = {TYPE_DOUBLE};
_param.double_value = GetEntry(_shift)[_mode];
return _param;
}

/* Getters */

/**
* Get smooth period.
*/
unsigned int GetSmoothPeriod() { return params.smooth_period; }

/**
* Get Chaikin period.
*/
unsigned int GetCHVPeriod() { return params.chv_period; }

/**
* Get smooth method.
*/
ENUM_MA_METHOD GetSmoothMethod() { return params.smooth_method; }

/* Setters */

/**
* Get smooth period.
*/
void SetSmoothPeriod(unsigned int _smooth_period) {
istate.is_changed = true;
params.smooth_period = _smooth_period;
}

/**
* Get Chaikin period.
*/
void SetCHVPeriod(unsigned int _chv_period) {
istate.is_changed = true;
params.chv_period = _chv_period;
}

/**
* Set smooth method.
*/
void SetSmoothMethod(ENUM_MA_METHOD _smooth_method) {
istate.is_changed = true;
params.smooth_method = _smooth_method;
}
};
20 changes: 14 additions & 6 deletions Indicators/Indi_CCI.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,18 @@ class Indi_CCI : public Indicator {
#endif
}

static double iCCIOnIndicator(Indicator *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period,
ENUM_APPLIED_PRICE _applied_price, int _shift = 0) {
double _indi_value_buffer[], _ohlc[4];
static double iCCIOnIndicator(Indicator *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _mode,
int _shift = 0) {
_indi.ValidateDataSourceMode(_mode);

double _indi_value_buffer[];
IndicatorDataEntry _entry(_indi.GetParams().GetMaxModes());

ArrayResize(_indi_value_buffer, _period);

for (int i = _shift; i < (int)_shift + (int)_period; i++) {
_indi[i].GetArray(_ohlc, 4);
_indi_value_buffer[i - _shift] = BarOHLC::GetAppliedPrice(_applied_price, _ohlc[0], _ohlc[1], _ohlc[2], _ohlc[3]);
// Getting value from single, selected buffer.
_indi_value_buffer[i - _shift] = _indi[i].GetValue<double>(_mode);
}

double d;
Expand Down Expand Up @@ -192,8 +194,14 @@ class Indi_CCI : public Indicator {
break;
case IDATA_INDICATOR:
// @fixit Somehow shift isn't used neither in MT4 nor MT5.
if (GetDataSourceMode() == -1) {
Print(
"Please use SetDataSourceMode() to select source indicator's buffer. Note that SetAppliedPrice() can be "
"used only with built-in or compiled indicators, but not with indicator-on-indicator mode.");
DebugBreak();
}
_value = Indi_CCI::iCCIOnIndicator(GetDataSource(), Get<string>(CHART_PARAM_SYMBOL),
Get<ENUM_TIMEFRAMES>(CHART_PARAM_TF), GetPeriod(), GetAppliedPrice(),
Get<ENUM_TIMEFRAMES>(CHART_PARAM_TF), GetPeriod(), GetDataSourceMode(),
_shift /* + params.shift*/);
break;
}
Expand Down
Loading

0 comments on commit 8ac67d3

Please sign in to comment.