Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions Convert.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class Convert {
/**
* Returns number of points per pip.
*/
static unsigned int PointsPerPip(string _symbol = NULL) {
static unsigned int PointsPerPip(string _symbol = NULL_STRING) {
return PointsPerPip((unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS));
}

Expand All @@ -137,7 +137,7 @@ class Convert {
/**
* Convert pips into price value.
*/
static double PipsToValue(double pips, string _symbol = NULL) {
static double PipsToValue(double pips, string _symbol = NULL_STRING) {
return PipsToValue(pips, (unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS));
}

Expand All @@ -149,7 +149,7 @@ class Convert {
/**
* Convert value into pips.
*/
static double ValueToPips(double value, string _symbol = NULL) {
static double ValueToPips(double value, string _symbol = NULL_STRING) {
return ValueToPips(value, (unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS));
}

Expand All @@ -161,7 +161,7 @@ class Convert {
/**
* Convert pips into points.
*/
static unsigned int PipsToPoints(double pips, string _symbol = NULL) {
static unsigned int PipsToPoints(double pips, string _symbol = NULL_STRING) {
return PipsToPoints(pips, (unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS));
}

Expand All @@ -173,15 +173,15 @@ class Convert {
/**
* Convert points into pips.
*/
static double PointsToPips(int64 pts, string _symbol = NULL) {
static double PointsToPips(int64 pts, string _symbol = NULL_STRING) {
return PointsToPips(pts, (unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS));
}

/**
* Convert points into price value.
*
*/
static double PointsToValue(int64 pts, int mode, string _symbol = NULL) {
static double PointsToValue(int64 pts, int mode, string _symbol = NULL_STRING) {
switch (mode) {
case 0: // Forex.
// In currencies a tick is a point.
Expand Down Expand Up @@ -226,7 +226,7 @@ class Convert {
/**
* Convert points into price value.
*/
static double PointsToValue(int64 pts, string _symbol = NULL) {
static double PointsToValue(int64 pts, string _symbol = NULL_STRING) {
return PointsToValue(pts, (int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_TRADE_CALC_MODE));
}

Expand All @@ -236,7 +236,7 @@ class Convert {
* @return
* Returns amount in a base currency based on the given the value.
*/
static double ValueToMoney(double value, string _symbol = NULL) {
static double ValueToMoney(double value, string _symbol = NULL_STRING) {
double _tick_value = SymbolInfoStatic::GetTickValue(_symbol) > 0 ? SymbolInfoStatic::GetTickValue(_symbol) : 1;
return value * _tick_value / SymbolInfoStatic::GetPointSize(_symbol);
}
Expand All @@ -247,7 +247,7 @@ class Convert {
* @return
* Returns value in points equivalent to the amount in a base currency.
*/
static float MoneyToValue(float money, float lot_size, string _symbol = NULL) {
static float MoneyToValue(float money, float lot_size, string _symbol = NULL_STRING) {
double _tick_value = SymbolInfoStatic::GetTickValue(_symbol) > 0 ? SymbolInfoStatic::GetTickValue(_symbol) : 1;
return money > 0 && lot_size > 0 ? float(money / _tick_value * SymbolInfoStatic::GetPointSize(_symbol) / lot_size)
: 0;
Expand All @@ -257,7 +257,7 @@ class Convert {
* Get the difference between two price values (in pips).
*/
static double GetValueDiffInPips(double price1, double price2, bool abs = false, int digits = 0,
string _symbol = NULL) {
string _symbol = NULL_STRING) {
digits = digits ? digits : (int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS);
return ValueToPips(abs ? fabs(price1 - price2) : (price1 - price2), digits);
}
Expand Down
2 changes: 1 addition & 1 deletion Exchange/Account/AccountMt.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ class AccountMt : public AccountBase {
* @return
* Returns true, when free margin is sufficient, false when insufficient or on error.
*/
bool IsFreeMargin(ENUM_ORDER_TYPE _cmd, double size_of_lot, string _symbol = NULL) {
bool IsFreeMargin(ENUM_ORDER_TYPE _cmd, double size_of_lot, string _symbol = NULL_STRING) {
bool _res = true;
// double margin = AccountFreeMarginCheck(_symbol, _cmd, size_of_lot);
if (GetLastError() == 134 /* NOT_ENOUGH_MONEY */) _res = false;
Expand Down
2 changes: 1 addition & 1 deletion Exchange/SymbolInfo/SymbolInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class SymbolInfo : public Object {
/**
* Class constructor given a symbol string.
*/
SymbolInfo(string _symbol = NULL) : symbol(_symbol), pip_size(GetPipSize()), symbol_digits(GetDigits()) {
SymbolInfo(string _symbol = NULL_STRING) : symbol(_symbol), pip_size(GetPipSize()), symbol_digits(GetDigits()) {
Select();
last_tick = GetTick();
// @todo: Test symbol with SymbolExists(_symbol)
Expand Down
2 changes: 1 addition & 1 deletion Exchange/SymbolInfo/SymbolInfo.struct.static.h
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ struct SymbolInfoStatic {
return ::SymbolInfoString(name, prop_id);
#else
printf("@fixme: %s\n", "SymbolInfoStatic::SymbolInfoString()");
return 0;
return NULL_STRING;
#endif
}
};
5 changes: 5 additions & 0 deletions File.extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,9 @@ unsigned int FileWrite(int file_handle, Arg&& arg, Args&&... args) {
return _memfs.FileWrite(file_handle, arg, args...);
}

// Currently we only support writting char arrays.
unsigned int FileWriteArray(int file_handle, ARRAY_REF(unsigned char, arr), int start_index, int count = INT_MAX) {
return _memfs.FileWriteArray(file_handle, arr, start_index, count);
}

#endif
6 changes: 3 additions & 3 deletions File.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class File {
Print("Cannot open file \"", path, "\" for reading. Error code: ", GetLastError(),
". Consider using path relative to \"" + terminalDataPath + "\\" + terminalSubfolder +
"\\Files\\\" as absolute paths may not work.");
return NULL;
return NULL_STRING;
}

string data = "";
Expand All @@ -116,7 +116,7 @@ class File {
static bool SaveFile(string path, string data, bool binary = false) {
ResetLastError();

int handle = FileOpen(path, FILE_WRITE | (binary ? FILE_BIN : FILE_TXT), "", CP_UTF8);
int handle = FileOpen(path, FILE_WRITE | (binary ? FILE_BIN : FILE_TXT), 0, CP_UTF8);

if (handle == INVALID_HANDLE) {
string terminalDataPath = TerminalInfoString(TERMINAL_DATA_PATH);
Expand All @@ -132,7 +132,7 @@ class File {
}

if (binary) {
uchar buffer[];
ARRAY(unsigned char, buffer);
StringToCharArray(data, buffer, 0, WHOLE_ARRAY, CP_UTF8);
FileWriteArray(handle, buffer, 0, ArraySize(buffer));
}
Expand Down
2 changes: 1 addition & 1 deletion Indicator/Indicator.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ class Indicator : public IndicatorData {
/**
* Sets indicator's params.
*/
void SetParams(IndicatorParams& _iparams) { iparams = _iparams; }
void SetParams(IndicatorParams& _iparams) { REF_TYPE(IndicatorParams)iparams = _iparams; }

/* Conditions */

Expand Down
21 changes: 20 additions & 1 deletion Indicator/IndicatorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,25 @@ class IndicatorBase : public Object {
*/
virtual IndicatorData* GetCandle(bool _warn_if_not_found = true, IndicatorData* _originator = nullptr) = 0;

/**
* Returns time of the current tick. Updated by EmitEntry() from the Tick indicator and stored in the Tick indicator
* in the hierarchy.
*/
virtual datetime GetTimeCurrent() {
// We shouldn't be here. It should be implemented in the IndicatorData class and overridden in the Tick indicator.
DebugBreak();
return datetime(0);
}

/**
* Updates time of the last tick. Called by EmitEntry() from the Tick indicator.
* @param _time_ms Timestamp in milliseconds.
*/
virtual void UpdateLastTickTimeMs(int64 _time_ms) {
// We shouldn't be here. It should be implemented in the IndicatorData class and overridden in the Tick indicator.
DebugBreak();
}

/**
* Returns the number of bars on the chart decremented by iparams.shift.
*/
Expand Down Expand Up @@ -424,7 +443,7 @@ class IndicatorBase : public Object {
}
};

#ifdef EMSCRIPTEN
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/bind.h>

Expand Down
51 changes: 37 additions & 14 deletions Indicator/IndicatorData.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ class IndicatorData : public IndicatorBase {
int calc_start_bar; // Index of the first valid bar (from 0).
int flags; // Flags such as INDI_FLAG_INDEXABLE_BY_SHIFT.
int last_tick_index; // Index of the last tick.
int64 first_tick_time_ms; // Time of the first ask/bid tick.
void* mydata;
bool last_tick_result; // Result of the last Tick() invocation.
ENUM_INDI_DATA_VS_TYPE retarget_ap_av; // Value storage type to be used as applied price/volume.
Expand Down Expand Up @@ -150,7 +149,7 @@ class IndicatorData : public IndicatorBase {
: do_draw(false), idparams(_idparams), indi_src(_indi_src) {
Init();
}
IndicatorData(const IndicatorDataParams& _idparams, ENUM_TIMEFRAMES _tf, string _symbol = NULL)
IndicatorData(const IndicatorDataParams& _idparams, ENUM_TIMEFRAMES _tf, string _symbol = NULL_STRING)
: do_draw(false), idparams(_idparams) {
Init();
}
Expand Down Expand Up @@ -211,12 +210,6 @@ class IndicatorData : public IndicatorBase {
*/
int GetFlags() { return flags; }

/**
* Returns time of the first ask/bid tick (time of first global OnTick()).
* Time is compatible with time generated by IndicatorTick, e.g., Indi_TickMt.
*/
int64 GetFirstTickTimeMs() { return first_tick_time_ms; }

/**
* Get full name of the indicator (with "over ..." part).
*/
Expand Down Expand Up @@ -892,6 +885,22 @@ class IndicatorData : public IndicatorBase {
HasSpecificValueStorage(INDI_DATA_VS_TYPE_VOLUME) && HasSpecificValueStorage(INDI_DATA_VS_TYPE_TICK_VOLUME);
}

/**
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider letting the tick indicator store and update the current tick time directly instead of delegating through GetTick() and PlatformTime, simplifying ownership and data flow.

You can simplify this without changing behavior by making the tick indicator itself the clear owner of the “current tick time” and removing the delegation chain through GetTick().

Right now:

  • IndicatorData::GetTimeCurrent()GetTick()->GetTimeCurrent()
  • IndicatorData::UpdateLastTickTimeMs()GetTick()->UpdateLastTickTimeMs(...)
  • EmitEntry()GetTick()->UpdateLastTickTimeMs(_entry.timestamp * 1000)

Combined with PlatformTime calling back into the indicator, this creates the circular indirection the other reviewer highlighted.

1. Store the tick time directly in IndicatorData

Give IndicatorData (specifically the tick indicator instance) a simple field to own the last tick time and implement the two methods directly, instead of delegating to GetTick():

// in IndicatorData (private or protected)
int64 last_tick_time_ms = 0;

// ...

// Returns time of the current tick.
datetime GetTimeCurrent() override {
  // If you need datetime in seconds:
  return (datetime)(last_tick_time_ms / 1000);
}

// Updates time of the last tick (ms).
void UpdateLastTickTimeMs(int64 _time_ms) override {
  last_tick_time_ms = _time_ms;
}

This removes the back-and-forth between different indicators for a value that is conceptually owned by the tick indicator.

2. Update EmitEntry to use the local setter

When emitting a tick entry, you can update the time via the local API, not via GetTick():

void EmitEntry(IndicatorDataEntry& _entry,
               ENUM_INDI_EMITTED_ENTRY_TYPE _type = INDI_EMITTED_ENTRY_TYPE_PARENT) {
  if (_type == INDI_EMITTED_ENTRY_TYPE_TICK) {
    // Tick indicator updates its own tick time
    UpdateLastTickTimeMs(_entry.timestamp * 1000);
  }

  for (int i = 0; i < ArraySize(listeners); ++i) {
    if (listeners[i].ObjectExists()) {
      listeners[i].Ptr() PTR_DEREF OnDataSourceEntry(_entry, _type);
    }
  }
}

If you still need a top-level “tick indicator in the hierarchy” abstraction, GetTick() can remain, but it no longer needs to be involved in the time plumbing.

3. Simplify PlatformTime usage (unidirectional flow)

With the above, PlatformTime can work with a primitive and avoid knowing about the indicator hierarchy:

  • When a tick is emitted, push the time into PlatformTime directly:
// wherever you integrate with PlatformTime:
if (_type == INDI_EMITTED_ENTRY_TYPE_TICK) {
  const int64 tick_time_ms = _entry.timestamp * 1000;
  UpdateLastTickTimeMs(tick_time_ms);       // indicator field
  PlatformTime::UpdateLastTickTimeMs(tick_time_ms); // platform field
}
  • PlatformTime no longer needs to call back into the indicator to fetch/set tick_time_ms; it just stores the primitive. That allows you to:

    • remove the need for PlatformTime to know about IndicatorData internals
    • likely remove or at least reduce the need to include PlatformTime.inline.h at the end of IndicatorData to resolve circular dependencies

If you still need inline definitions, you can keep PlatformTime APIs purely in terms of primitive types:

// PlatformTime.inline.h
inline void PlatformTime::UpdateLastTickTimeMs(int64 tick_time_ms) {
  last_tick_time_ms = tick_time_ms;
}

inline datetime PlatformTime::TimeCurrent() const {
  return (datetime)(last_tick_time_ms / 1000);
}

This keeps all functionality (tick indicators still drive both indicator hierarchy and PlatformTime), but the flow is now unidirectional and the coupling/indirection are significantly reduced.

* Returns time of the current tick. Updated by EmitEntry() from the Tick indicator and stored in the Tick indicator
* in the hierarchy.
*/
datetime GetTimeCurrent() override {
return GetTick() PTR_DEREF GetTimeCurrent();
}

/**
* Updates time of the last tick. Called by EmitEntry() from the Tick indicator.
* @param _time_ms Timestamp in milliseconds.
*/
void UpdateLastTickTimeMs(int64 _time_ms) override {
GetTick() PTR_DEREF UpdateLastTickTimeMs(_time_ms);
}

bool Tick(int _global_tick_index) {
if (last_tick_index == _global_tick_index) {
#ifdef __debug_indicator__
Expand All @@ -901,10 +910,11 @@ class IndicatorData : public IndicatorBase {
return last_tick_result;
}

if (_global_tick_index == 0) {
// Time of the first tick must be compatible with time generated by IndicatorTick, e.g., Indi_TickMt.
first_tick_time_ms = TimeCurrent() * 1000;
}
// Will allow indicator to update time of the current tick to be used by current indicator.
// It is required to update time before ticking data source and indicators in hierarchy because they could use time
// of the current tick for their calculations, e.g., to check if new tick belongs to new bar or not.
// @todo OnUpdatePlatformTime(GetTimeCurrent());


last_tick_index = _global_tick_index;

Expand Down Expand Up @@ -2000,6 +2010,13 @@ class IndicatorData : public IndicatorBase {
* Sends entry to listening indicators.
*/
void EmitEntry(IndicatorDataEntry& _entry, ENUM_INDI_EMITTED_ENTRY_TYPE _type = INDI_EMITTED_ENTRY_TYPE_PARENT) {
if (_type == INDI_EMITTED_ENTRY_TYPE_TICK) {
// Updating time of the last emitted tick entry in the Tick indicator in the hierarchy to be later retrieved by
// GetTimeCurrent() method of indicators or global TimeCurrent()/Platform::TimeCurrent() when indicator is ran
// with Tester class.
GetTick() PTR_DEREF UpdateLastTickTimeMs(_entry.timestamp * 1000);
}

for (int i = 0; i < ArraySize(listeners); ++i) {
if (listeners[i].ObjectExists()) {
listeners[i].Ptr() PTR_DEREF OnDataSourceEntry(_entry, _type);
Expand Down Expand Up @@ -2219,7 +2236,7 @@ IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIn
int GetBarsFromStart(IndicatorBase* _indi) { return _indi PTR_DEREF GetBars(); }
#endif

#ifdef EMSCRIPTEN
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/bind.h>

Expand All @@ -2229,7 +2246,13 @@ EMSCRIPTEN_BINDINGS(IndicatorData) {
.function("SetSource", emscripten::optional_override([](IndicatorData& self, IndicatorData* base) {
self.SetDataSource(base);
}),
emscripten::allow_raw_pointer<emscripten::arg<0>>());
emscripten::allow_raw_pointer<emscripten::arg<1>>());
}

#endif

// Provide inline definitions for PlatformTime methods that need complete IndicatorBase/IndicatorData types.
// This must come after the IndicatorData class body so both types are complete.
#ifndef __MQL__
#include "../Platform/PlatformTime.inline.h"
#endif
5 changes: 4 additions & 1 deletion Indicator/IndicatorTf.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ class IndicatorTf : public IndicatorCandle<TFP, double, ItemsHistoryTfCandleProv
/**
* Class constructor with parameters.
*/
IndicatorTf(const TFP& _icparams, const IndicatorDataParams& _idparams) { Init(); }
IndicatorTf(const TFP& _icparams, const IndicatorDataParams& _idparams)
: IndicatorCandle<TFP, double, ItemsHistoryTfCandleProvider<double>>(_icparams, _idparams) {
Init();
}

/**
* Gets indicator's time-frame.
Expand Down
2 changes: 1 addition & 1 deletion Indicator/IndicatorTf.struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
struct IndicatorTfParams : IndicatorParams {
ChartTf tf;
// Struct constructor.
IndicatorTfParams(string _name, ENUM_TIMEFRAMES _tf) : IndicatorParams(_name) { tf.SetTf(_tf); }
IndicatorTfParams(string _name, ENUM_TIMEFRAMES _tf) : IndicatorParams(_name), tf(_tf) { }
// Copy constructor.
IndicatorTfParams(const IndicatorTfParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) {
THIS_REF = _params;
Expand Down
23 changes: 21 additions & 2 deletions Indicator/IndicatorTick.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class IndicatorTick : public Indicator<TS> {
SymbolInfoProp symbol_props;
TickBarCounter counter;

// Time of the last tick (with passed periods functionality).
DateTime last_tick_time;

protected:
/* Protected methods */

Expand Down Expand Up @@ -83,7 +86,7 @@ class IndicatorTick : public Indicator<TS> {
*/
IndicatorTick(string _symbol, const TS& _itparams, const IndicatorDataParams& _idparams,
IndicatorData* _indi_src = NULL, int _indi_mode = 0)
: Indicator<TS>(_itparams, _idparams, _indi_src, _indi_mode), history(THIS_PTR) {
: Indicator<TS>(_itparams, _idparams, _indi_src, _indi_mode), history(THIS_PTR), last_tick_time(false) {
itparams = _itparams;
if (_indi_src != NULL) {
THIS_ATTR SetDataSource(_indi_src, _indi_mode);
Expand All @@ -92,7 +95,7 @@ class IndicatorTick : public Indicator<TS> {
Init();
}
IndicatorTick(string _symbol, ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "")
: Indicator<TS>(_itype, _shift, _name), history(THIS_PTR) {
: Indicator<TS>(_itype, _shift, _name), history(THIS_PTR), last_tick_time(false) {
symbol = _symbol;
Comment on lines 86 to 99
Init();
}
Expand All @@ -112,6 +115,22 @@ class IndicatorTick : public Indicator<TS> {
*/
datetime GetBarTime(int _rel_shift = 0) override { return history.GetItemTimeByShift(_rel_shift); }

/**
* Updates time of the last tick. Called by EmitEntry() from the Tick indicator.
*/
virtual void UpdateLastTickTimeMs(int64 _time_ms) override {
Print("Updating last tick time (sec): ", _time_ms / 1000, " for indicator ", this->GetFullName());
Comment on lines +121 to +122
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Per-tick Print in IndicatorTick::UpdateLastTickTimeMs will severely impact performance and spam logs.

Because UpdateLastTickTimeMs is called for every tick, this log line will generate extremely large log volumes and noticeably slow both live and backtest runs.

Please either guard this behind a compile-time debug flag / debug-only build, or remove it once the feature is validated. If you still need detailed tracing, consider a rate-limited logger instead of unconditional per-tick printing.

Suggested implementation:

  /**
   * Updates time of the last tick. Called by EmitEntry() from the Tick indicator.
   * Logging is guarded by DEBUG_INDICATOR_TICK_LOG to avoid per-tick log spam in normal builds.
   */
  virtual void UpdateLastTickTimeMs(int64 _time_ms) override {
  #ifdef DEBUG_INDICATOR_TICK_LOG
    Print("Updating last tick time (sec): ", _time_ms / 1000, " for indicator ", this->GetFullName());
  #endif
    _last_tick_time.Update(_time_ms / 1000);
  }
  1. Define DEBUG_INDICATOR_TICK_LOG only in debug builds or when you explicitly need detailed per-tick tracing. For example, in a central config/header used only for debugging, or via your build system’s preprocessor definitions.
  2. Once the feature is fully validated, you may want to remove the guarded Print entirely if you no longer need per-tick tracing.

last_tick_time.Update(_time_ms / 1000);
}

/**
* Returns time of the current tick. Updated by EmitEntry() from the Tick indicator and stored in the Tick indicator
* in the hierarchy.
*/
datetime GetTimeCurrent() override {
return last_tick_time.dt_curr.GetTimestamp();
}

/**
* Gets ask price for a given date and time. Return current ask price if _dt wasn't passed or is 0.
*/
Expand Down
4 changes: 2 additions & 2 deletions Indicator/tests/classes/IndicatorTfDummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ class IndicatorTfDummy : public IndicatorTf<IndicatorTfDummyParams> {

#ifdef __debug_indicator__
Print(GetFullName(), " got new tick at ", entry.timestamp,
" (" + TimeToString(entry.timestamp) + "): ", entry.ToString<double>());
" (" + TimeToString(entry.timestamp, TIME_DATE | TIME_MINUTES | TIME_SECONDS) + "): ", entry.ToString<double>());
#endif
}
};

#ifdef EMSCRIPTEN
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add tests for the new WASM/EMSCRIPTEN bindings and time-handling changes (PlatformTime/Indicator time plumbing).

These changes alter how time is sourced and propagated for the WASM build (e.g., PlatformTime depending on the current tick indicator, new GetTimeCurrent/UpdateLastTickTimeMs behavior, INDI_EMITTED_ENTRY_TYPE_TICK in EmitEntry), but there are no new tests validating this, particularly in the C++/WASM path.

Please add a dedicated C++/WASM test (e.g., Indicator/tests/PlatformTime.test.cpp) that:

  • Runs a Tick provider plus one or more indicators under the WASM-aware test harness.
  • Asserts that TimeCurrent(), PlatformTime::TimeCurrent(), and IndicatorBase::GetTimeCurrent() all return the tick time from the Tick indicator.
  • Covers edge cases such as: no current tick indicator set, indicator hierarchies (time propagates from the Tick indicator), and multiple ticks with increasing timestamps to confirm DateTime/period-start behavior.

This will ensure the new WASM time plumbing matches MQL runtime expectations and catches regressions early.

#ifdef __EMSCRIPTEN__
#include <emscripten/bind.h>

EMSCRIPTEN_BINDINGS(IndicatorTfDummyParams) { emscripten::value_object<IndicatorTfDummyParams>("indicators.TfParams"); }
Expand Down
Loading
Loading