mql5/Experts/testRefactor2/SignalEngine.mqh

229 lignes
8,1 Kio
MQL5
Brut Lien permanent Vue normale Historique

2026-02-01 21:39:33 +01:00
//+------------------------------------------------------------------+
//| SignalEngine.mqh – indikátory a výpočet signálů |
//+------------------------------------------------------------------+
#property copyright "TestRefactor"
#property strict
#ifndef __SIGNAL_ENGINE_MQH__
#define __SIGNAL_ENGINE_MQH__
#include "Context.mqh"
#include "Logger.mqh"
struct SSignalResult {
bool ok;
bool buySignal;
bool sellSignal;
double smaDistancePoints;
bool trendUp;
double volume;
};
struct SLastBarValues {
double slowMa0, slowMa1, fastMa0, fastMa1, rsi0;
};
struct SH1TrendResult {
bool ok;
bool trendUp;
};
//+------------------------------------------------------------------+
//| CSignalEngine – drží handly, počítá SMA distance, trend, signály|
//+------------------------------------------------------------------+
class CSignalEngine {
private:
string m_symbol;
SContext m_ctx;
CLogger *m_log;
int m_handleFastMa;
int m_handleSlowMa;
int m_handleRsi;
int m_handleH1TrendMa;
int m_handleTf1Ma;
int m_handleTf2Ma;
datetime m_lastBarTime;
public:
CSignalEngine() : m_symbol(""), m_handleFastMa(INVALID_HANDLE), m_handleSlowMa(INVALID_HANDLE),
m_handleRsi(INVALID_HANDLE), m_handleH1TrendMa(INVALID_HANDLE), m_handleTf1Ma(INVALID_HANDLE),
m_handleTf2Ma(INVALID_HANDLE), m_lastBarTime(0), m_log(NULL) {}
void SetLogger(CLogger *log) { m_log = log; }
void SetSymbol(string symbol) { m_symbol = symbol; }
void SetContext(const SContext &ctx) { m_ctx = ctx; }
bool Init() {
m_handleFastMa = iMA(m_symbol, PERIOD_CURRENT, m_ctx.fastMaPeriod, 0, MODE_SMA, PRICE_CLOSE);
m_handleSlowMa = iMA(m_symbol, PERIOD_CURRENT, m_ctx.slowMaPeriod, 0, MODE_SMA, PRICE_CLOSE);
m_handleRsi = iRSI(m_symbol, PERIOD_CURRENT, m_ctx.rsiPeriod, PRICE_CLOSE);
m_handleH1TrendMa = INVALID_HANDLE;
if(m_ctx.h1TrendMaPeriod > 0) {
m_handleH1TrendMa = iMA(m_symbol, PERIOD_H1, m_ctx.h1TrendMaPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(m_handleH1TrendMa == INVALID_HANDLE) {
if(m_log) m_log.Error("Error creating H1 trend MA");
return false;
}
}
if(m_ctx.timeframe1MaPeriod > 0) {
m_handleTf1Ma = iMA(m_symbol, m_ctx.timeframe1, m_ctx.timeframe1MaPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(m_handleTf1Ma == INVALID_HANDLE) {
if(m_log) m_log.Error("Error creating TF1 trend MA");
return false;
}
}
if(m_ctx.timeframe2MaPeriod > 0) {
m_handleTf2Ma = iMA(m_symbol, m_ctx.timeframe2, m_ctx.timeframe2MaPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(m_handleTf2Ma == INVALID_HANDLE) {
if(m_log) m_log.Error("Error creating TF2 trend MA");
return false;
}
}
if(m_handleFastMa == INVALID_HANDLE || m_handleSlowMa == INVALID_HANDLE || m_handleRsi == INVALID_HANDLE) {
if(m_log) m_log.Error("Error creating indicators");
return false;
}
return true;
}
void Deinit() {
if(m_handleFastMa != INVALID_HANDLE) IndicatorRelease(m_handleFastMa);
if(m_handleSlowMa != INVALID_HANDLE) IndicatorRelease(m_handleSlowMa);
if(m_handleRsi != INVALID_HANDLE) IndicatorRelease(m_handleRsi);
if(m_handleH1TrendMa != INVALID_HANDLE) IndicatorRelease(m_handleH1TrendMa);
if(m_handleTf1Ma != INVALID_HANDLE) IndicatorRelease(m_handleTf1Ma);
if(m_handleTf2Ma != INVALID_HANDLE) IndicatorRelease(m_handleTf2Ma);
m_handleFastMa = m_handleSlowMa = m_handleRsi = m_handleH1TrendMa = m_handleTf1Ma = m_handleTf2Ma = INVALID_HANDLE;
}
bool IsNewBar() {
datetime time = iTime(m_symbol, PERIOD_CURRENT, 0);
if(time != m_lastBarTime) {
m_lastBarTime = time;
return true;
}
return false;
}
SSignalResult GetSignals() {
SSignalResult r;
r.ok = false;
r.buySignal = false;
r.sellSignal = false;
r.smaDistancePoints = 0;
r.trendUp = true;
r.volume = m_ctx.lotSize;
double slowMaArray[];
if(CopyBuffer(m_handleSlowMa, 0, 1, 2, slowMaArray) != 2) return r;
ArraySetAsSeries(slowMaArray, true);
double fastMaArray[];
if(CopyBuffer(m_handleFastMa, 0, 1, 2, fastMaArray) != 2) return r;
ArraySetAsSeries(fastMaArray, true);
double rsiArray[];
if(CopyBuffer(m_handleRsi, 0, 1, 1, rsiArray) != 1) return r;
ArraySetAsSeries(rsiArray, true);
r.smaDistancePoints = MathAbs(fastMaArray[0] - slowMaArray[0]) / _Point;
bool distanceOk = (m_ctx.smaMinDistancePoints <= 0) || (r.smaDistancePoints >= m_ctx.smaMinDistancePoints);
bool trendOkBuy = true, trendOkSell = true;
if(m_handleH1TrendMa != INVALID_HANDLE) {
double h1MaArray[];
if(CopyBuffer(m_handleH1TrendMa, 0, 1, 1, h1MaArray) == 1) {
ArraySetAsSeries(h1MaArray, true);
double closeH1 = iClose(m_symbol, PERIOD_H1, 1);
trendOkBuy = (closeH1 > h1MaArray[0]);
trendOkSell = (closeH1 < h1MaArray[0]);
r.trendUp = trendOkBuy;
}
}
r.buySignal = (fastMaArray[0] > slowMaArray[0] && fastMaArray[1] < slowMaArray[1] && rsiArray[0] < m_ctx.rsiOverbought && distanceOk && trendOkBuy);
r.sellSignal = (fastMaArray[0] < slowMaArray[0] && fastMaArray[1] > slowMaArray[1] && rsiArray[0] > m_ctx.rsiOversold && distanceOk && trendOkSell);
double minVol = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MIN);
double maxVol = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MAX);
double stepVol = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_STEP);
double vol = r.volume;
if(vol < minVol) vol = minVol;
if(vol > maxVol) vol = maxVol;
if(stepVol > 0) vol = minVol + MathRound((vol - minVol) / stepVol) * stepVol;
r.volume = vol;
r.ok = true;
return r;
}
SH1TrendResult GetH1Trend() {
SH1TrendResult r;
r.ok = false;
r.trendUp = true;
if(m_handleH1TrendMa == INVALID_HANDLE) return r;
double h1MaArray[];
if(CopyBuffer(m_handleH1TrendMa, 0, 1, 1, h1MaArray) != 1) return r;
double closeH1 = iClose(m_symbol, PERIOD_H1, 1);
r.trendUp = (closeH1 > h1MaArray[0]);
r.ok = true;
return r;
}
SH1TrendResult GetTf1Trend() {
SH1TrendResult r;
r.ok = false;
r.trendUp = true;
if(m_handleTf1Ma == INVALID_HANDLE) return r;
double maArray[];
if(CopyBuffer(m_handleTf1Ma, 0, 1, 1, maArray) != 1) return r;
double close = iClose(m_symbol, m_ctx.timeframe1, 1);
r.trendUp = (close > maArray[0]);
r.ok = true;
return r;
}
SH1TrendResult GetTf2Trend() {
SH1TrendResult r;
r.ok = false;
r.trendUp = true;
if(m_handleTf2Ma == INVALID_HANDLE) return r;
double maArray[];
if(CopyBuffer(m_handleTf2Ma, 0, 1, 1, maArray) != 1) return r;
double close = iClose(m_symbol, m_ctx.timeframe2, 1);
r.trendUp = (close > maArray[0]);
r.ok = true;
return r;
}
bool IsBuyDirectionValid() {
SH1TrendResult tf1 = GetTf1Trend();
SH1TrendResult tf2 = GetTf2Trend();
if(!tf1.ok || !tf2.ok) return true;
return tf1.trendUp && tf2.trendUp;
}
bool IsSellDirectionValid() {
SH1TrendResult tf1 = GetTf1Trend();
SH1TrendResult tf2 = GetTf2Trend();
if(!tf1.ok || !tf2.ok) return true;
return !tf1.trendUp && !tf2.trendUp;
}
SLastBarValues GetLastBarValues() {
SLastBarValues r;
r.slowMa0 = r.slowMa1 = r.fastMa0 = r.fastMa1 = r.rsi0 = 0;
double slowMaArray[], fastMaArray[], rsiArray[];
if(CopyBuffer(m_handleSlowMa, 0, 1, 2, slowMaArray) != 2) return r;
if(CopyBuffer(m_handleFastMa, 0, 1, 2, fastMaArray) != 2) return r;
if(CopyBuffer(m_handleRsi, 0, 1, 1, rsiArray) != 1) return r;
ArraySetAsSeries(slowMaArray, true);
ArraySetAsSeries(fastMaArray, true);
ArraySetAsSeries(rsiArray, true);
r.slowMa0 = slowMaArray[0]; r.slowMa1 = slowMaArray[1];
r.fastMa0 = fastMaArray[0]; r.fastMa1 = fastMaArray[1];
r.rsi0 = rsiArray[0];
return r;
}
};
#endif