Skip to content

Commit

Permalink
WIP. Somehow last entry of Tick indicator has missing prices.
Browse files Browse the repository at this point in the history
  • Loading branch information
nseam committed May 17, 2022
1 parent 49d7edf commit 275c0c2
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 28 deletions.
10 changes: 10 additions & 0 deletions Indicator/IndicatorTick.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ class IndicatorTick : public Indicator<TS> {
Init();
}

/**
* Gets ask price for a given, optional shift.
*/
virtual double GetAsk(int _shift = 0) { return GetEntry(_shift).GetValue<double>(INDI_TICK_MODE_PRICE_ASK); }

/**
* Gets bid price for a given, optional shift.
*/
virtual double GetBid(int _shift = 0) { return GetEntry(_shift).GetValue<double>(INDI_TICK_MODE_PRICE_BID); }

/**
* Returns value storage of given kind.
*/
Expand Down
29 changes: 29 additions & 0 deletions IndicatorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,16 @@ class IndicatorBase : public Object {
*/
int GetDataSourceMode() { return indi_src_mode; }

/**
* Checks whether there is Candle-featured in the hierarchy.
*/
bool HasCandleInHierarchy() { return GetCandle(false) != nullptr; }

/**
* Checks whether there is Tick-featured in the hierarchy.
*/
bool HasTickInHierarchy() { return GetTick(false) != nullptr; }

/**
* Traverses source indicators' hierarchy and tries to find OHLC-featured
* indicator. IndicatorCandle satisfies such requirements.
Expand Down Expand Up @@ -619,6 +629,25 @@ class IndicatorBase : public Object {
*/
virtual string GetDescriptiveName() { return GetName(); }

/**
* Returns symbol and optionally TF to be used e.g., to identify
*/
string GetSymbolTf(string _separator = "@") {
if (!HasCandleInHierarchy()) {
return "";
}

// Symbol is available throught Tick indicator at the end of the hierarchy.
string _res = GetSymbol();

if (HasCandleInHierarchy()) {
// TF is available throught Candle indicator at the end of the hierarchy.
_res += _separator + ChartTf::TfToString(GetTf());
}

return _res;
}

/* Setters */

/**
Expand Down
1 change: 0 additions & 1 deletion Strategy.enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ enum ENUM_STRATEGY_PARAM {
STRAT_PARAM_SOFT, // Signal open filter time
STRAT_PARAM_SOL, // Signal open level
STRAT_PARAM_SOM, // Signal open method
STRAT_PARAM_TF, // Timeframe
STRAT_PARAM_TFM, // Tick filter method
STRAT_PARAM_TYPE, // Type
STRAT_PARAM_WEIGHT, // Weight
Expand Down
45 changes: 34 additions & 11 deletions Strategy.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class Strategy : public Taskable<DataParamEntry> {
Dict<int, double> ddata;
Dict<int, float> fdata;
Dict<int, int> idata;
Ref<IndicatorBase> indi_candle; // Candle indicator to be a base for all indicators.
Ref<IndicatorBase> indi_source; // Candle or Tick indicator as a price source.
DictStruct<int, Ref<IndicatorBase>> indicators; // Indicators list.
Log logger; // Log instance.
MqlTick last_tick;
Expand Down Expand Up @@ -123,8 +123,8 @@ class Strategy : public Taskable<DataParamEntry> {
/**
* Class constructor.
*/
Strategy(StgParams &_sparams, TradeParams &_tparams, IndicatorBase *_indi_candle, string _name = "")
: sparams(_sparams), trade(new Trade(_tparams, _indi_candle)), indi_candle(_indi_candle) {
Strategy(StgParams &_sparams, TradeParams &_tparams, IndicatorBase *_indi_source, string _name = "")
: sparams(_sparams), trade(new Trade(_tparams, _indi_source)), indi_source(_indi_source) {
// Initialize variables.
name = _name;
MqlTick _tick = {0};
Expand Down Expand Up @@ -276,6 +276,20 @@ class Strategy : public Taskable<DataParamEntry> {
*/
Strategy *GetStratTp() { return strat_tp; }

/**
* Returns Candle or Tick indicator bound to this strategy.
*/
IndicatorBase *GetSource() { return indi_source.Ptr(); }

/**
* Executes OnTick() on every attached indicator.
*/
void Tick() {
for (DictIterator<int, Ref<IndicatorBase>> it = indicators.Begin(); it.IsValid(); ++it) {
it.Value() REF_DEREF Tick();
}
}

/**
* Get strategy's name.
*/
Expand Down Expand Up @@ -324,17 +338,15 @@ class Strategy : public Taskable<DataParamEntry> {
// return StringFormat("%s%s[%s];s:%gp%s", _prefix != "" ? _prefix + ": " : "", name, trade REF_DEREF
// chart.TfToString(), GetCurrSpread(), _suffix != "" ? "| " + _suffix : "");

return StringFormat("%s%s[%s]%s", _prefix, name,
ChartTf::TfToString(trade REF_DEREF Get<ENUM_TIMEFRAMES>(CHART_PARAM_TF)), _suffix);
return StringFormat("%s%s[%s]%s", _prefix, name, trade REF_DEREF GetSource() PTR_DEREF GetSymbolTf(), _suffix);
}

/**
* Get strategy's order close comment.
*/
string GetOrderCloseComment(string _prefix = "", string _suffix = "") {
// @todo: Add spread.
return StringFormat("%s%s[%s]%s", _prefix, name,
ChartTf::TfToString(trade REF_DEREF Get<ENUM_TIMEFRAMES>(CHART_PARAM_TF)), _suffix);
return StringFormat("%s%s[%s]%s", _prefix, name, trade REF_DEREF GetSource() PTR_DEREF GetSymbolTf(), _suffix);
}

/**
Expand Down Expand Up @@ -665,8 +677,14 @@ class Strategy : public Taskable<DataParamEntry> {
* _oparams Order parameters to update before the open.
*/
virtual void OnOrderOpen(OrderParams &_oparams) {
if (!GetSource() PTR_DEREF HasCandleInHierarchy()) {
Print("In order this method to work, you have to pass Candle-featured indicator as source!");
DebugBreak();
return;
}

int _index = 0;
ENUM_TIMEFRAMES _stf = Get<ENUM_TIMEFRAMES>(STRAT_PARAM_TF);
ENUM_TIMEFRAMES _stf = GetSource() PTR_DEREF GetTf();
unsigned int _stf_secs = ChartTf::TfToSeconds(_stf);
if (sparams.order_close_time != 0) {
long _close_time_arg = sparams.order_close_time > 0 ? sparams.order_close_time * 60
Expand Down Expand Up @@ -740,6 +758,12 @@ class Strategy : public Taskable<DataParamEntry> {
* Returns true when tick should be processed, otherwise false.
*/
virtual bool TickFilter(const MqlTick &_tick, const int _method) {
if (!GetSource() PTR_DEREF HasCandleInHierarchy()) {
Print("In order this method to work you have to pass Candle-featured indicator as source!");
DebugBreak();
return false;
}

bool _res = _method >= 0;
bool _val;
int _method_abs = fabs(_method);
Expand Down Expand Up @@ -778,7 +802,7 @@ class Strategy : public Taskable<DataParamEntry> {
if (METHOD(_method_abs, 4)) { // 16
// Process ticks in the middle of the bar.
_val = (trade REF_DEREF GetSource() PTR_DEREF GetBarTime() +
(ChartTf::TfToSeconds(trade REF_DEREF Get<ENUM_TIMEFRAMES>(CHART_PARAM_TF)) / 2)) == TimeCurrent();
(ChartTf::TfToSeconds(trade REF_DEREF GetSource() PTR_DEREF GetTf()) / 2)) == TimeCurrent();
_res = _method > 0 ? _res & _val : _res | _val;
}
if (METHOD(_method_abs, 5)) { // 32
Expand All @@ -788,8 +812,7 @@ class Strategy : public Taskable<DataParamEntry> {
}
if (METHOD(_method_abs, 6)) { // 64
// Process every 10th of the bar.
_val =
TimeCurrent() % (int)(ChartTf::TfToSeconds(trade REF_DEREF Get<ENUM_TIMEFRAMES>(CHART_PARAM_TF)) / 10) == 0;
_val = TimeCurrent() % (int)(ChartTf::TfToSeconds(trade REF_DEREF GetSource() PTR_DEREF GetTf()) / 10) == 0;
_res = _method > 0 ? _res & _val : _res | _val;
}
if (METHOD(_method_abs, 7)) { // 128
Expand Down
6 changes: 0 additions & 6 deletions Strategy.struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,6 @@ struct StgParams {
return (T)price_profit_method;
case STRAT_PARAM_PSM:
return (T)price_stop_method;
case STRAT_PARAM_TF:
return (T)tf.GetTf();
case STRAT_PARAM_TFM:
return (T)tick_filter_method;
case STRAT_PARAM_TYPE:
Expand Down Expand Up @@ -279,10 +277,6 @@ struct StgParams {
case STRAT_PARAM_PSM: // Price stop method
price_stop_method = (int)_value;
return;
case STRAT_PARAM_TF:
// Main timeframe where strategy operates on.
tf = (ENUM_TIMEFRAMES)_value;
return;
case STRAT_PARAM_TFM: // Tick filter method
tick_filter_method = (int)_value;
return;
Expand Down
4 changes: 1 addition & 3 deletions Trade.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,7 @@ class Trade : public Taskable<DataParamEntry> {
_request.deviation = 10;
_request.magic = _magic > 0 ? _magic : tparams.Get<long>(TRADE_PARAM_MAGIC_NO);
_request.symbol = GetSource() PTR_DEREF GetSymbol();
DebugBreak();
// X _request.price = SymbolInfoStatic::GetOpenOffer(_request.symbol, _type);
// V _request.price = GetTickSource() PTR_DEREF GetSymbolInfo() PTR_DEREF GetOpenOffer(_request.symbol, _type);
_request.price = GetSource() PTR_DEREF GetOpenOffer(_type);
_request.type = _type;
_request.type_filling = Order::GetOrderFilling(_request.symbol);
_request.volume = _volume > 0 ? _volume : tparams.Get<float>(TRADE_PARAM_LOT_SIZE);
Expand Down
18 changes: 11 additions & 7 deletions tests/StrategyTest-RSI.mq5
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,17 @@
class Stg_RSI : public Strategy {
public:
// Class constructor.
void Stg_RSI(StgParams &_sparams, TradeParams &_tparams, ChartParams &_cparams, string _name = "")
: Strategy(_sparams, _tparams, chart_params_defaults, _name) {}
void Stg_RSI(StgParams &_sparams, TradeParams &_tparams, IndicatorBase *_indi_source, string _name = "")
: Strategy(_sparams, _tparams, _indi_source, _name) {}

static Stg_RSI *Init(ENUM_TIMEFRAMES _tf = NULL) {
ChartParams _cparams(_tf);
static Stg_RSI *Init(IndicatorBase *_indi_source) {
IndiRSIParams _indi_params(12, PRICE_OPEN, 0);
StgParams _stg_params;
TradeParams _tparams;
Strategy *_strat = new Stg_RSI(_stg_params, _tparams, _cparams, "RSI");
_strat.SetIndicator(new Indi_RSI(_indi_params));
Strategy *_strat = new Stg_RSI(_stg_params, _tparams, _indi_source, "RSI");
IndicatorBase *_indi_rsi = new Indi_RSI(_indi_params);
_strat.SetIndicator(_indi_rsi);
_indi_rsi PTR_DEREF SetDataSource(_indi_source);
return _strat;
}

Expand Down Expand Up @@ -93,7 +94,7 @@ int OnInit() {
_candles.Ptr().SetDataSource(_ticks.Ptr());

// Initialize strategy instance.
stg_rsi = Stg_RSI::Init(PERIOD_CURRENT);
stg_rsi = Stg_RSI::Init(_candles.Ptr());
stg_rsi REF_DEREF SetName("Stg_RSI");
stg_rsi REF_DEREF Set<long>(STRAT_PARAM_ID, 1234);

Expand Down Expand Up @@ -124,6 +125,9 @@ int OnInit() {
* Implements OnTick().
*/
void OnTick() {
// Strategy will tick all attached indicators.
stg_rsi REF_DEREF Tick();

static MqlTick _tick_last;
MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol);
if (_tick_new.time % 60 < _tick_last.time % 60) {
Expand Down

0 comments on commit 275c0c2

Please sign in to comment.