1468 lines
33 KiB
Plaintext
1468 lines
33 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL4 Signal Draw Global Library
|
|
// ---------------------------------------------------
|
|
// saherelm useful tools and definitions ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
// Includes Logger library ...
|
|
#include "../Libraries/x-saherelm.log.lib.mq4"
|
|
|
|
//
|
|
// Includes Models library ...
|
|
#include "../Libraries/x-saherelm.models.lib.mq4"
|
|
|
|
//
|
|
// Includes Drawing library ...
|
|
#include "../Libraries/x-saherelm.draw.lib.mq4"
|
|
|
|
//
|
|
// Start Signal Functions ...
|
|
//
|
|
//
|
|
// Generate a Unique ID for Signal ...
|
|
string GenerateSignalTAG(
|
|
const XSignal &signal,
|
|
const string tag = "",
|
|
const string longSignalLabel = "",
|
|
const string shortSignalLabel = ""
|
|
) {
|
|
//
|
|
// Generate Propper Label for Signal ...
|
|
string label = signal.type == X_LONG ? longSignalLabel : signal.type == X_SHORT ? shortSignalLabel : "UN_KNOWN";
|
|
|
|
//
|
|
// Generate Unique String Identifier for Signal ...
|
|
string result = tag +
|
|
"_[ID:" + IntegerToString(signal.id) + "]" +
|
|
"_[" + label + "]" +
|
|
"_[" + signal.symbol + "]" +
|
|
"_[Time:" + TimeToStr(signal.time) + "]" +
|
|
"_[TP:" + DoubleToString(signal.tp) + "]" +
|
|
"_[SL:" + DoubleToString(signal.sl) + "]";
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Logging a Signal ...
|
|
void LogSignal(
|
|
const XSignal &signal,
|
|
const string tag = "",
|
|
const string longSignalLabel = "",
|
|
const string shortSignalLabel = ""
|
|
) {
|
|
//
|
|
// Generate Message ...
|
|
string signalMessage = GenerateSignalTAG(
|
|
signal,
|
|
tag,
|
|
longSignalLabel,
|
|
shortSignalLabel
|
|
);
|
|
|
|
//
|
|
LogMessage(signalMessage);
|
|
}
|
|
|
|
//
|
|
// Retrieve Price Action Candlestick Type ...
|
|
double GetPCandleType(const int bar_index) {
|
|
//
|
|
double result = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
pcrtIndicatorName,
|
|
0,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve OSC Snapshot State ...
|
|
XOSCState GetOSCState(const int bar_index) {
|
|
//
|
|
// Temp Result ...
|
|
XOSCState result = {};
|
|
|
|
//
|
|
// Start Extract Data from Oscillator ...
|
|
//
|
|
//
|
|
// Fast OSC ...
|
|
double fastOSC = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
oscIndicatorName,
|
|
fastOSCLength,
|
|
fastOSCMultiplier,
|
|
slowOSCLength,
|
|
slowOSCMultiplier,
|
|
0, // Fast OSC Buffer Index ...
|
|
bar_index
|
|
);
|
|
result.fastOSC = fastOSC;
|
|
|
|
//
|
|
// Prev FastOSC ...
|
|
double fastOSCPrev = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
oscIndicatorName,
|
|
fastOSCLength,
|
|
fastOSCMultiplier,
|
|
slowOSCLength,
|
|
slowOSCMultiplier,
|
|
0, // Fast OSC Buffer Index ...
|
|
bar_index + 1
|
|
);
|
|
result.fastOSCPrev = fastOSCPrev;
|
|
|
|
//
|
|
// Slow OSC ...
|
|
double slowOSC = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
oscIndicatorName,
|
|
fastOSCLength,
|
|
fastOSCMultiplier,
|
|
slowOSCLength,
|
|
slowOSCMultiplier,
|
|
1, // Slow OSC Buffer Index ...
|
|
bar_index
|
|
);
|
|
result.slowOSC = slowOSC;
|
|
|
|
//
|
|
// Prev Slow OSC ...
|
|
double slowOSCPrev = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
oscIndicatorName,
|
|
fastOSCLength,
|
|
fastOSCMultiplier,
|
|
slowOSCLength,
|
|
slowOSCMultiplier,
|
|
1, // Slow OSC Buffer Index ...
|
|
bar_index + 1
|
|
);
|
|
result.slowOSCPrev = slowOSCPrev;
|
|
|
|
//
|
|
// Power OSC ...
|
|
double powerOSC = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
oscIndicatorName,
|
|
fastOSCLength,
|
|
fastOSCMultiplier,
|
|
slowOSCLength,
|
|
slowOSCMultiplier,
|
|
2, // Power OSC Buffer Index ...
|
|
bar_index
|
|
);
|
|
result.powerOSC = powerOSC;
|
|
|
|
//
|
|
double powerOSCPrev = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
oscIndicatorName,
|
|
fastOSCLength,
|
|
fastOSCMultiplier,
|
|
slowOSCLength,
|
|
slowOSCMultiplier,
|
|
2, // Power OSC Buffer Index ...
|
|
bar_index + 1
|
|
);
|
|
result.powerOSCPrev = powerOSCPrev;
|
|
|
|
//
|
|
// Var OSC ...
|
|
double varOSC = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
oscIndicatorName,
|
|
fastOSCLength,
|
|
fastOSCMultiplier,
|
|
slowOSCLength,
|
|
slowOSCMultiplier,
|
|
3, // Var OSC Buffer Index ...
|
|
bar_index
|
|
);
|
|
result.varOSC = varOSC;
|
|
|
|
//
|
|
double varOSCPrev = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
oscIndicatorName,
|
|
fastOSCLength,
|
|
fastOSCMultiplier,
|
|
slowOSCLength,
|
|
slowOSCMultiplier,
|
|
3, // Var OSC Buffer Index ...
|
|
bar_index + 1
|
|
);
|
|
result.varOSCPrev = varOSCPrev;
|
|
|
|
//
|
|
// Tan FS OSC ...
|
|
double tanFSOSC = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
oscIndicatorName,
|
|
fastOSCLength,
|
|
fastOSCMultiplier,
|
|
slowOSCLength,
|
|
slowOSCMultiplier,
|
|
4, // Tan F/S OSC Buffer Index ...
|
|
bar_index
|
|
);
|
|
result.tanFSOSC = tanFSOSC;
|
|
//
|
|
// End Extract Data from Oscillator ...
|
|
//
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Ma Snapshot State ...
|
|
XMaState GetMaState(
|
|
const int bar_index,
|
|
int fastMaPeriod = 20,
|
|
ENUM_MA_METHOD fastMaMethod = MODE_EMA,
|
|
ENUM_APPLIED_PRICE fastMaAppliedPrice = PRICE_CLOSE,
|
|
int slowMaPeriod = 50,
|
|
ENUM_MA_METHOD slowMaMethod = MODE_EMA,
|
|
ENUM_APPLIED_PRICE slowMaAppliedPrice = PRICE_CLOSE
|
|
) {
|
|
//
|
|
XMaState result = {};
|
|
|
|
//
|
|
double fastMa = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
maIndicatorName,
|
|
fastMaPeriod,
|
|
fastMaMethod,
|
|
fastMaAppliedPrice,
|
|
slowMaPeriod,
|
|
slowMaMethod,
|
|
slowMaAppliedPrice,
|
|
0,
|
|
bar_index
|
|
);
|
|
result.fastMa = fastMa;
|
|
|
|
//
|
|
double fastMaPrev = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
maIndicatorName,
|
|
fastMaPeriod,
|
|
fastMaMethod,
|
|
fastMaAppliedPrice,
|
|
slowMaPeriod,
|
|
slowMaMethod,
|
|
slowMaAppliedPrice,
|
|
0,
|
|
bar_index + 1
|
|
);
|
|
result.fastMaPrev = fastMaPrev;
|
|
|
|
//
|
|
double slowMa = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
maIndicatorName,
|
|
fastMaPeriod,
|
|
fastMaMethod,
|
|
fastMaAppliedPrice,
|
|
slowMaPeriod,
|
|
slowMaMethod,
|
|
slowMaAppliedPrice,
|
|
1,
|
|
bar_index
|
|
);
|
|
result.slowMa = slowMa;
|
|
|
|
//
|
|
double slowMaPrev = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
maIndicatorName,
|
|
fastMaPeriod,
|
|
fastMaMethod,
|
|
fastMaAppliedPrice,
|
|
slowMaPeriod,
|
|
slowMaMethod,
|
|
slowMaAppliedPrice,
|
|
1,
|
|
bar_index + 1
|
|
);
|
|
result.slowMaPrev = slowMaPrev;
|
|
|
|
//
|
|
Print(fastMa, slowMa, fastMaPrev, slowMaPrev);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve MACD info ...
|
|
XMACDState GetMACDState() {
|
|
//
|
|
XMACDState result = {};
|
|
|
|
//
|
|
// TODO: Complete this later ...
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check OSC Has Signal ...
|
|
// default Method ...
|
|
XSignalInfo OSCHasSignal(
|
|
const XOSCState &oscState,
|
|
const double &minimumSignalPower,
|
|
const double &minimumVarPower
|
|
) {
|
|
//
|
|
// Genrate Temp Result ...
|
|
XSignalInfo result = {};
|
|
|
|
//
|
|
bool isCrossedOver = oscState.fastOSC > oscState.slowOSC && !(oscState.fastOSCPrev > oscState.slowOSCPrev);
|
|
bool hasLongSignal = isCrossedOver && oscState.powerOSC >= minimumSignalPower;
|
|
result.hasLongSignal = hasLongSignal;
|
|
|
|
//
|
|
bool isCrossedUnder = oscState.fastOSC < oscState.slowOSC && !(oscState.fastOSCPrev < oscState.slowOSCPrev);
|
|
bool hasShortSignal = isCrossedUnder && oscState.powerOSC >= minimumSignalPower;
|
|
result.hasShortSignal = hasShortSignal;
|
|
|
|
//
|
|
bool hasSignal = hasLongSignal || hasShortSignal;
|
|
result.hasSignal = hasSignal;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check OSC Has Signal ...
|
|
// Method 1 ...
|
|
XSignalInfo OSCHasSignal_1(
|
|
const XOSCState &oscState,
|
|
const double &minimumSignalPower,
|
|
const double &minimumVarPower
|
|
) {
|
|
//
|
|
static bool canSignalLong = true;
|
|
static bool canSignalShort = true;
|
|
|
|
//
|
|
// Genrate Temp Result ...
|
|
XSignalInfo result = {};
|
|
//return result;
|
|
|
|
//
|
|
// bool hasLongSignal = false;
|
|
bool isCrossedOver = oscState.fastOSC > oscState.slowOSC &&
|
|
!(oscState.fastOSCPrev > oscState.slowOSCPrev);
|
|
bool hasLongSignal = isCrossedOver &&
|
|
oscState.powerOSC >= minimumSignalPower &&
|
|
oscState.varOSC >= minimumVarPower;
|
|
result.hasLongSignal = hasLongSignal;
|
|
// if (hasLongSignal) {
|
|
// canSignalLong = false;
|
|
// }
|
|
|
|
//
|
|
// bool hasShortSignal = false;
|
|
bool isCrossedUnder = oscState.fastOSC < oscState.slowOSC && !(oscState.fastOSCPrev < oscState.slowOSCPrev);
|
|
bool hasShortSignal = isCrossedUnder &&
|
|
oscState.powerOSC >= minimumSignalPower &&
|
|
oscState.varOSC >= minimumVarPower;
|
|
result.hasShortSignal = hasShortSignal;
|
|
// if (hasShortSignal) {
|
|
// canSignalShort = false;
|
|
// }
|
|
|
|
//
|
|
bool hasSignal = hasLongSignal || hasShortSignal;
|
|
result.hasSignal = hasSignal;
|
|
|
|
//
|
|
// Fix can Signal Long ...
|
|
//if (oscState.fastOSC >= 0 && !canSignalLong) {
|
|
// canSignalLong = true;
|
|
//}
|
|
|
|
//
|
|
// Fix can Signal Short ...
|
|
//if (oscState.fastOSC <= 1 && !canSignalShort) {
|
|
// canSignalShort = true;
|
|
//}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check OSC Has Signal ...
|
|
// Method 2 ...
|
|
XSignalInfo OSCHasSignal_2(
|
|
const XOSCState &oscState,
|
|
const int &bar_index
|
|
) {
|
|
//
|
|
static bool canSignalLong = true;
|
|
static bool canSignalShort = true;
|
|
|
|
//
|
|
// Genrate Temp Result ...
|
|
XSignalInfo result = {};
|
|
//return result;
|
|
|
|
//
|
|
// bool hasLongSignal = false;
|
|
bool isCrossedOver = oscState.fastOSC > oscState.slowOSC &&
|
|
!(oscState.fastOSCPrev > oscState.slowOSCPrev);
|
|
|
|
//
|
|
// Get Prev Price Action Candle Type ...
|
|
int pCandleType = (int) GetPCandleType(bar_index + 1);
|
|
|
|
bool hasLongSignal = isCrossedOver
|
|
&& oscState.slowOSC > 0.5
|
|
&& oscState.varOSC > 0;
|
|
|
|
// && oscState.powerOSC >= 0.006
|
|
// && oscState.powerOSC - oscState.powerOSCPrev > 0
|
|
// && oscState.tanFSOSC >= 0.06
|
|
|
|
// && (
|
|
// pCandleType == X_CT_HAMMER ||
|
|
// pCandleType == X_CT_BULLISH_BELT ||
|
|
// pCandleType == X_CT_MORNING_STAR ||
|
|
// pCandleType == X_CT_BULLISH_KICKER ||
|
|
// pCandleType == X_CT_BULLISH_HARAMI ||
|
|
// pCandleType == X_CT_INVERTED_HAMMER ||
|
|
// pCandleType == X_CT_BULLISH_ENGULFING ||
|
|
// pCandleType == 0
|
|
// )
|
|
result.hasLongSignal = hasLongSignal;
|
|
if (hasLongSignal) {
|
|
//
|
|
// Print("Tan: " + oscState.tanFSOSC);
|
|
}
|
|
// if (hasLongSignal) {
|
|
// canSignalLong = false;
|
|
// }
|
|
|
|
//
|
|
// bool hasShortSignal = false;
|
|
bool isCrossedUnder = oscState.fastOSC < oscState.slowOSC && !(oscState.fastOSCPrev < oscState.slowOSCPrev);
|
|
bool hasShortSignal = false;
|
|
result.hasShortSignal = hasShortSignal;
|
|
// if (hasShortSignal) {
|
|
// canSignalShort = false;
|
|
// }
|
|
|
|
//
|
|
bool hasSignal = hasLongSignal || hasShortSignal;
|
|
result.hasSignal = hasSignal;
|
|
|
|
//
|
|
// Fix can Signal Long ...
|
|
//if (oscState.fastOSC >= 0 && !canSignalLong) {
|
|
// canSignalLong = true;
|
|
//}
|
|
|
|
//
|
|
// Fix can Signal Short ...
|
|
//if (oscState.fastOSC <= 1 && !canSignalShort) {
|
|
// canSignalShort = true;
|
|
//}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Ma Has Signal ...
|
|
XSignalInfo MaHasSignal(
|
|
const XMaState &maState,
|
|
const int &bar_index
|
|
) {
|
|
//
|
|
XSignalInfo result = {};
|
|
result.hasSignal = false;
|
|
|
|
//
|
|
// Long ...
|
|
bool isFastCrossOverSlow = maState.fastMa > maState.slowMa
|
|
&& !(maState.fastMaPrev > maState.slowMaPrev);
|
|
bool hasLongSignal = isFastCrossOverSlow;
|
|
result.hasLongSignal = hasLongSignal;
|
|
|
|
//
|
|
// Short ...
|
|
bool isFastCrossUnderSlow = maState.fastMa < maState.slowMa
|
|
&& !(maState.fastMaPrev < maState.slowMaPrev);
|
|
bool hasShortSignal = isFastCrossUnderSlow;
|
|
result.hasShortSignal = hasShortSignal;
|
|
|
|
//
|
|
bool hasSignal = hasLongSignal || hasShortSignal;
|
|
result.hasSignal = hasSignal;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Swing SL ...
|
|
XSLInfo GetSwngSL(const int &bar_index) {
|
|
//
|
|
// Temp result ...
|
|
XSLInfo result = {};
|
|
|
|
//
|
|
// Start Reading SL ...
|
|
//
|
|
//
|
|
// Long SL ...
|
|
double longSL = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
slIndicatorName,
|
|
slLoopback, // SL IND Inputs ...
|
|
slThrshold, // SL IND Inputs ...
|
|
0, // Long SL Buffer Index ...
|
|
bar_index
|
|
);
|
|
longSL = NormalizeDouble(longSL, _Digits);
|
|
result.longSL = longSL;
|
|
|
|
//
|
|
// Short SL ...
|
|
double shortSL = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
slIndicatorName,
|
|
slLoopback, // SL IND Inputs ...
|
|
slThrshold, // SL IND Inputs ...
|
|
1, // Short SL Buffer Index ...
|
|
bar_index
|
|
);
|
|
shortSL = NormalizeDouble(shortSL, _Digits);
|
|
result.shortSL = shortSL;
|
|
//
|
|
// End Reading SL ...
|
|
//
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading TP based on SwingSL ...
|
|
XTPInfo GetTP(const int &bar_index) {
|
|
//
|
|
// Temp result ...
|
|
XTPInfo result = {};
|
|
|
|
//
|
|
// Start Reading TP ...
|
|
//
|
|
//
|
|
// Long TP ...
|
|
double longTP = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
tpIndicatorName,
|
|
slLoopback, // TP IND Inputs ...
|
|
slThrshold, // SL IND Inputs ...
|
|
riskToRewardRatio, // TP IND Inputs ...
|
|
0, // Long TP Buffer Index ...
|
|
bar_index
|
|
);
|
|
longTP = NormalizeDouble(longTP, _Digits);
|
|
result.longTP = longTP;
|
|
|
|
//
|
|
// Short TP ...
|
|
double shortTP = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
tpIndicatorName,
|
|
slLoopback, // TP IND Inputs ...
|
|
slThrshold, // SL IND Inputs ...
|
|
riskToRewardRatio, // TP IND Inputs ...
|
|
1, // Short TP Buffer Index ...
|
|
bar_index
|
|
);
|
|
shortTP = NormalizeDouble(shortTP, _Digits);
|
|
result.shortTP = shortTP;
|
|
//
|
|
// End Reading TP ...
|
|
//
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Signal ...
|
|
// Default Method ...
|
|
XSignalRequest CalculateOSCSignal(
|
|
const int bar_index,
|
|
const double minimumSignalPower = 0.03,
|
|
const double minimumVarPower = 0.01
|
|
) {
|
|
//
|
|
XSignalRequest result = {};
|
|
result.hasSignal = false;
|
|
result.type = X_NONE;
|
|
|
|
//
|
|
// Reading Oscillator State ...
|
|
XOSCState oscState = GetOSCState(bar_index);
|
|
|
|
//
|
|
// Generate Signals From OSC ...
|
|
XSignalInfo signalInfo = OSCHasSignal(
|
|
oscState,
|
|
minimumSignalPower,
|
|
minimumVarPower
|
|
);
|
|
|
|
//
|
|
result.hasSignal = signalInfo.hasSignal;
|
|
if (!signalInfo.hasSignal) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// increase signal count ...
|
|
signalCount++;
|
|
|
|
//
|
|
// increase long/short signal count ...
|
|
if (signalInfo.hasLongSignal) {
|
|
longSignalCount++;
|
|
} else if (signalInfo.hasShortSignal) {
|
|
shortSignalCount++;
|
|
}
|
|
|
|
//
|
|
// Retrieve Open Price ...
|
|
double openPrice = iOpen(_Symbol, _Period, bar_index);
|
|
openPrice = NormalizeDouble(openPrice, _Digits);
|
|
|
|
//
|
|
// Signal Entry Price ...
|
|
double signalEntryPrice = signalInfo.hasLongSignal ? Ask : Bid;
|
|
signalEntryPrice = NormalizeDouble(signalEntryPrice, _Digits);
|
|
|
|
//
|
|
// Signal Time ...
|
|
datetime signalTime = iTime(_Symbol, _Period, bar_index);
|
|
|
|
//
|
|
// Signal Type ...
|
|
X_SIGNAL_TYPE signalType = signalInfo.hasLongSignal ? X_LONG : X_SHORT;
|
|
result.type = signalType;
|
|
|
|
//
|
|
// Reading SL ...
|
|
XSLInfo slInfo = GetSwngSL(bar_index);
|
|
|
|
//
|
|
// Reading TP ...
|
|
XTPInfo tpInfo = GetTP(bar_index);
|
|
|
|
//
|
|
// Generate Signal SL ...
|
|
double signalSL = signalInfo.hasLongSignal ? slInfo.longSL : slInfo.shortSL;
|
|
|
|
//
|
|
// Generate Signal TP ...
|
|
double signalTP = signalInfo.hasLongSignal ? tpInfo.longTP : tpInfo.shortTP;
|
|
|
|
//
|
|
// Generate XSignal Instance based on received Data ...
|
|
XSignal signal = {};
|
|
signal.id = signalCount;
|
|
signal.sl = signalSL;
|
|
signal.tp = signalTP;
|
|
signal.time = signalTime;
|
|
signal.type = signalType;
|
|
signal.symbol = _Symbol;
|
|
// signal.openPrice = openPrice;
|
|
// signal.entryPrice = signalEntryPrice;
|
|
|
|
//
|
|
result.signal = signal;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Signal ...
|
|
// Method 1 ...
|
|
XSignalRequest CalculateSignal_1(
|
|
const int bar_index,
|
|
const double minimumSignalPower = 0.03,
|
|
const double minimumVarPower = 0.01
|
|
) {
|
|
//
|
|
XSignalRequest result = {};
|
|
result.hasSignal = false;
|
|
result.type = X_NONE;
|
|
|
|
//
|
|
// Reading Oscillator State ...
|
|
XOSCState oscState = GetOSCState(bar_index);
|
|
|
|
//
|
|
// Retrieve Price Action Theory based Candlestick Type ...
|
|
int pCandleType = (int) GetPCandleType(bar_index);
|
|
|
|
//
|
|
// Generate Signals From OSC ...
|
|
XSignalInfo signalInfo = OSCHasSignal_1(
|
|
oscState,
|
|
minimumSignalPower,
|
|
minimumVarPower
|
|
);
|
|
|
|
//
|
|
result.hasSignal = signalInfo.hasSignal;
|
|
if (!signalInfo.hasSignal) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Price Action Candlestick Verification on Long Signals ...
|
|
if (signalInfo.hasLongSignal) {
|
|
//
|
|
// Check current Candle Type based on Price Action Theory ...
|
|
if (pCandleType == X_P_CT_BEARISH) {
|
|
//
|
|
result.hasSignal = false;
|
|
return result;
|
|
} else if (pCandleType == X_P_CT_NEUTRAL) {
|
|
//
|
|
// Here we must loop through back bar indexes until find a
|
|
// candle which no NEUTRAL ...
|
|
int barCounter = bar_index + 1;
|
|
int prevUnNeutralPCandleType = -1;
|
|
while(
|
|
barCounter <= Bars &&
|
|
prevUnNeutralPCandleType == -1
|
|
) {
|
|
//
|
|
int cPCType = (int) GetPCandleType(barCounter);
|
|
if (cPCType != X_P_CT_NEUTRAL) {
|
|
prevUnNeutralPCandleType = cPCType;
|
|
} else {
|
|
barCounter++;
|
|
}
|
|
}
|
|
|
|
//
|
|
result.hasSignal = false;
|
|
if (prevUnNeutralPCandleType != X_P_CT_BULLISH) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result.hasSignal = true;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get Price Action Candlestick Verification on Short Signals ...
|
|
if (signalInfo.hasShortSignal) {
|
|
//
|
|
// Check current Candle Type based on Price Action Theory ...
|
|
if (pCandleType == X_P_CT_BULLISH) {
|
|
//
|
|
result.hasSignal = false;
|
|
return result;
|
|
} else if (pCandleType == X_P_CT_NEUTRAL) {
|
|
//
|
|
// Here we must loop through back bar indexes until find a
|
|
// candle which no NEUTRAL ...
|
|
int barCounter = bar_index + 1;
|
|
int prevUnNeutralPCandleType = -1;
|
|
while(
|
|
barCounter <= Bars &&
|
|
prevUnNeutralPCandleType == -1
|
|
) {
|
|
//
|
|
int cPCType = (int) GetPCandleType(barCounter);
|
|
if (cPCType != X_P_CT_NEUTRAL) {
|
|
prevUnNeutralPCandleType = cPCType;
|
|
} else {
|
|
barCounter++;
|
|
}
|
|
}
|
|
|
|
//
|
|
result.hasSignal = false;
|
|
if (prevUnNeutralPCandleType != X_P_CT_BEARISH) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result.hasSignal = true;
|
|
}
|
|
}
|
|
|
|
//
|
|
// increase signal count ...
|
|
signalCount++;
|
|
|
|
//
|
|
// increase long/short signal count ...
|
|
if (signalInfo.hasLongSignal) {
|
|
longSignalCount++;
|
|
} else if (signalInfo.hasShortSignal) {
|
|
shortSignalCount++;
|
|
}
|
|
|
|
//
|
|
// Retrieve Open Price ...
|
|
double openPrice = iOpen(_Symbol, _Period, bar_index);
|
|
openPrice = NormalizeDouble(openPrice, _Digits);
|
|
|
|
//
|
|
// Signal Entry Price ...
|
|
RefreshRates();
|
|
double signalEntryPrice = signalInfo.hasLongSignal ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
// signalInfo.hasLongSignal ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
signalEntryPrice = NormalizeDouble(signalEntryPrice, _Digits);
|
|
|
|
//
|
|
// Signal Time ...
|
|
datetime signalTime = iTime(_Symbol, _Period, bar_index);
|
|
|
|
//
|
|
// Signal Type ...
|
|
X_SIGNAL_TYPE signalType = signalInfo.hasLongSignal ? X_LONG : X_SHORT;
|
|
result.type = signalType;
|
|
|
|
//
|
|
// Reading SL ...
|
|
XSLInfo slInfo = GetSwngSL(bar_index);
|
|
|
|
//
|
|
// Reading TP ...
|
|
XTPInfo tpInfo = GetTP(bar_index);
|
|
|
|
//
|
|
// Generate Signal SL ...
|
|
double signalSL = signalInfo.hasLongSignal ? slInfo.longSL : slInfo.shortSL;
|
|
|
|
//
|
|
// Generate Signal TP ...
|
|
double signalTP = signalInfo.hasLongSignal ? tpInfo.longTP : slInfo.longSL; // tpInfo.shortTP;
|
|
|
|
//
|
|
// Generate XSignal Instance based on received Data ...
|
|
XSignal signal = {};
|
|
signal.id = signalCount;
|
|
signal.sl = signalSL;
|
|
signal.tp = signalTP;
|
|
signal.time = signalTime;
|
|
signal.type = signalType;
|
|
signal.symbol = _Symbol;
|
|
// signal.openPrice = openPrice;
|
|
// signal.entryPrice = signalEntryPrice;
|
|
|
|
//
|
|
result.signal = signal;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Signal ...
|
|
// Method 2 ...
|
|
XSignalRequest CalculateSignal_2(const int bar_index) {
|
|
//
|
|
XSignalRequest result = {};
|
|
result.hasSignal = false;
|
|
result.type = X_NONE;
|
|
|
|
//
|
|
// Reading Oscillator State ...
|
|
XOSCState oscState = GetOSCState(bar_index);
|
|
|
|
//
|
|
// Generate Signals From OSC ...
|
|
XSignalInfo signalInfo = OSCHasSignal_2(
|
|
oscState,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
result.hasSignal = signalInfo.hasSignal;
|
|
if (!signalInfo.hasSignal) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// increase signal count ...
|
|
signalCount++;
|
|
|
|
//
|
|
// increase long/short signal count ...
|
|
if (signalInfo.hasLongSignal) {
|
|
longSignalCount++;
|
|
} else if (signalInfo.hasShortSignal) {
|
|
shortSignalCount++;
|
|
}
|
|
|
|
//
|
|
// Signal Time ...
|
|
datetime signalTime = iTime(_Symbol, _Period, bar_index);
|
|
|
|
//
|
|
// Signal Type ...
|
|
X_SIGNAL_TYPE signalType = signalInfo.hasLongSignal ? X_LONG : X_SHORT;
|
|
result.type = signalType;
|
|
|
|
//
|
|
// Reading SL ...
|
|
XSLInfo slInfo = GetSwngSL(bar_index);
|
|
|
|
//
|
|
// Reading TP ...
|
|
XTPInfo tpInfo = GetTP(bar_index);
|
|
|
|
//
|
|
// Generate Signal SL ...
|
|
double signalSL = signalInfo.hasLongSignal ? slInfo.longSL : slInfo.shortSL;
|
|
|
|
//
|
|
// Generate Signal TP ...
|
|
double signalTP = signalInfo.hasLongSignal ? tpInfo.longTP : tpInfo.shortTP;
|
|
|
|
//
|
|
// Generate XSignal Instance based on received Data ...
|
|
XSignal signal = {};
|
|
signal.id = signalCount;
|
|
signal.sl = signalSL;
|
|
signal.tp = signalTP;
|
|
signal.time = signalTime;
|
|
signal.type = signalType;
|
|
signal.symbol = _Symbol;
|
|
|
|
//
|
|
result.signal = signal;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Signal ...
|
|
// Using Ma ...
|
|
XSignalRequest CalculateMaSignal(const int bar_index) {
|
|
//
|
|
XSignalRequest result = {};
|
|
result.hasSignal = false;
|
|
result.type = X_NONE;
|
|
|
|
//
|
|
// Reading Moving Average State ...
|
|
XMaState maState = GetMaState(bar_index);
|
|
|
|
//
|
|
// Generate Signals From OSC ...
|
|
XSignalInfo signalInfo = MaHasSignal(
|
|
maState,
|
|
bar_index
|
|
);
|
|
Print("Ma HasSignal: ", signalInfo.hasSignal);
|
|
|
|
//
|
|
result.hasSignal = signalInfo.hasSignal;
|
|
if (!signalInfo.hasSignal) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// increase signal count ...
|
|
signalCount++;
|
|
|
|
//
|
|
// increase long/short signal count ...
|
|
if (signalInfo.hasLongSignal) {
|
|
longSignalCount++;
|
|
} else if (signalInfo.hasShortSignal) {
|
|
shortSignalCount++;
|
|
}
|
|
|
|
//
|
|
// Signal Time ...
|
|
datetime signalTime = iTime(_Symbol, _Period, bar_index);
|
|
|
|
//
|
|
// Signal Type ...
|
|
X_SIGNAL_TYPE signalType = signalInfo.hasLongSignal ? X_LONG : X_SHORT;
|
|
result.type = signalType;
|
|
|
|
//
|
|
// Reading SL ...
|
|
XSLInfo slInfo = GetSwngSL(bar_index);
|
|
|
|
//
|
|
// Reading TP ...
|
|
XTPInfo tpInfo = GetTP(bar_index);
|
|
|
|
//
|
|
// Generate Signal SL ...
|
|
double signalSL = signalInfo.hasLongSignal ? slInfo.longSL : slInfo.shortSL;
|
|
|
|
//
|
|
// Generate Signal TP ...
|
|
double signalTP = signalInfo.hasLongSignal ? tpInfo.longTP : tpInfo.shortTP;
|
|
|
|
//
|
|
// Generate XSignal Instance based on received Data ...
|
|
XSignal signal = {};
|
|
signal.id = signalCount;
|
|
signal.sl = signalSL;
|
|
signal.tp = signalTP;
|
|
signal.time = signalTime;
|
|
signal.type = signalType;
|
|
signal.symbol = _Symbol;
|
|
|
|
//
|
|
result.signal = signal;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Count Open Positions ...
|
|
int CountOpenPositions() {
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
// Loop through Orders ...
|
|
for (int i = 0; i < OrdersTotal(); i++) {
|
|
//
|
|
// Select indexed Order ...
|
|
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
|
|
//
|
|
// Check Order ...
|
|
if (OrderSymbol() == _Symbol) {
|
|
result++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return Result ...
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Trading On Signals ...
|
|
void TradeOnSignal(
|
|
const XSignal &signal,
|
|
double tradeVolume = 0.1,
|
|
string signalTag = "X-Signal",
|
|
string longSignalLabel = "X-Long",
|
|
color longSignalColor = clrLime,
|
|
string shortSignalLabel = "X-Short",
|
|
color shortSignalColor = clrRed
|
|
) {
|
|
//
|
|
// Start Genearting required data ...
|
|
//
|
|
//
|
|
// START implementing Money Management ...
|
|
//
|
|
if (tradeCount == 0) {
|
|
//
|
|
initialBalance = AccountBalance();
|
|
|
|
//
|
|
string msg = StringConcatenate("Initial Account Balance: ", initialBalance);
|
|
LogMessage(msg);
|
|
}
|
|
|
|
//
|
|
// Retrieve current Account balance
|
|
double currentBalance = AccountBalance();
|
|
if (currentBalance < initialBalance / 2) {
|
|
//
|
|
string msg = StringConcatenate("Account Balance less than minimum allowed, trading off ...");
|
|
LogMessage(msg);
|
|
|
|
//
|
|
return;
|
|
}
|
|
//
|
|
// END implementing Money Management ...
|
|
//
|
|
|
|
//
|
|
// Detect Trade is Long or Short ...
|
|
bool isLongSignal = signal.type == X_LONG;
|
|
|
|
//
|
|
// Generate Trade Comment ...
|
|
string tradeComment = GenerateSignalTAG(
|
|
signal,
|
|
signalTag,
|
|
longSignalLabel,
|
|
shortSignalLabel
|
|
);
|
|
|
|
//
|
|
// Detect Trade Operation ...
|
|
int tradeOperation = isLongSignal ? OP_BUY : OP_SELL;
|
|
|
|
//
|
|
// Detect Trade Color ...
|
|
color tradeColor = isLongSignal ? longSignalColor : shortSignalColor;
|
|
//
|
|
// End Genearting required data ...
|
|
//
|
|
|
|
//
|
|
double price = 0;
|
|
double closePrice = 0;
|
|
double priceGap = 0;
|
|
double tp = 0;
|
|
double sl = 0;
|
|
|
|
//
|
|
RefreshRates();
|
|
|
|
//
|
|
// Calculating Open, SL, TP for Positions ...
|
|
if (isLongSignal) {
|
|
//
|
|
// Long Positions ...
|
|
|
|
//
|
|
// Prices ...
|
|
price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
closePrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
|
|
//
|
|
priceGap = closePrice - price;
|
|
|
|
//
|
|
// SL ...
|
|
if (signal.sl > 0) {
|
|
sl = signal.sl + priceGap;
|
|
}
|
|
|
|
//
|
|
// TP ...
|
|
if (signal.tp > 0) {
|
|
tp = signal.tp - priceGap;
|
|
}
|
|
} else {
|
|
//
|
|
// Short Positions ...
|
|
|
|
//
|
|
// Prices ...
|
|
price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
closePrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
|
|
//
|
|
// SL ...
|
|
if (signal.sl > 0) {
|
|
sl = signal.sl - priceGap;
|
|
}
|
|
|
|
//
|
|
// TP ...
|
|
if (signal.tp > 0) {
|
|
tp = signal.tp + priceGap;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ignore last TP and SL Calculation and Use Default ...
|
|
// sl = signal.sl;
|
|
// tp = signal.tp;
|
|
|
|
//
|
|
// Normalize Prices ...
|
|
price = NormalizeDouble(price, _Digits);
|
|
sl = NormalizeDouble(sl, _Digits);
|
|
tp = NormalizeDouble(tp, _Digits);
|
|
|
|
//
|
|
// Define Trade Variables ...
|
|
double slGap = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
|
|
|
|
//
|
|
// Price Check ...
|
|
if (price == 0) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Prevent Open Trading when price doesn't fill slGap ...'
|
|
if (signal.sl > 0 && signal.sl < slGap) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Prevent Open Trading when price doesn't fill slGap ...'
|
|
if (signal.tp > 0 && signal.tp < slGap) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Fix Signal SL and Price Same issue ...
|
|
if (price == sl || MathAbs(price - sl) <= slGap) {
|
|
//
|
|
// string msg = StringConcatenate("id: ", signal.id , ", Price: ", price, ", sl: ", sl);
|
|
// LogMessage(msg);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Placing Order ...
|
|
int orderTicket = OrderSend(
|
|
signal.symbol,
|
|
tradeOperation,
|
|
tradeVolume,
|
|
price,
|
|
3,
|
|
sl,
|
|
tp,
|
|
tradeComment,
|
|
(int)signal.id,
|
|
0,
|
|
tradeColor
|
|
);
|
|
|
|
//
|
|
if (orderTicket >= 0) {
|
|
tradeCount++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Draw Signal Shapes on Chart ...
|
|
bool DrawSignalShape(
|
|
const XSignal &signal,
|
|
long chartID = 0,
|
|
int subWindowID = 0,
|
|
const double positionThresholdFactor = 10,
|
|
string signalTag = "X-Signal",
|
|
string longSignalLabel = "X-Long",
|
|
color longSignalColor = clrAqua,
|
|
string shortSignalLabel = "X-Short",
|
|
color shortSignalColor = clrFuchsia
|
|
) {
|
|
//
|
|
// Generate isLongSignal Var ...
|
|
bool isLongSignal = signal.type == X_LONG;
|
|
|
|
//
|
|
// Signal Bar Index ...
|
|
int bar_index = iBarShift(
|
|
_Symbol,
|
|
_Period,
|
|
signal.time
|
|
);
|
|
|
|
//
|
|
// START Draw Signal Arrow ...
|
|
//
|
|
//
|
|
// Arrow Shape Name ...
|
|
string arrowName = StringConcatenate(signalTag, "_Arrow_", signal.id);
|
|
|
|
//
|
|
// Arrow Price ...
|
|
double arrowPrice = 0;
|
|
if (isLongSignal) {
|
|
//
|
|
arrowPrice = iLow(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
arrowPrice = arrowPrice - (positionThresholdFactor * _Point);
|
|
} else {
|
|
//
|
|
arrowPrice = iHigh(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
arrowPrice = arrowPrice + (positionThresholdFactor * _Point);
|
|
}
|
|
|
|
//
|
|
// Arrow Code ...
|
|
uchar arrowCode = isLongSignal ? SYMBOL_ARROWUP : SYMBOL_ARROWDOWN;
|
|
|
|
//
|
|
// Arrow Anchor Point ...
|
|
ENUM_ARROW_ANCHOR arrowAnchorPoint = isLongSignal ? ANCHOR_BOTTOM : ANCHOR_TOP;
|
|
|
|
//
|
|
// Arrow Color ...
|
|
color arrowColor = isLongSignal ? longSignalColor : shortSignalColor;
|
|
|
|
//
|
|
// Draw Signal Arrow Shape ...
|
|
bool result = DrawArrow(
|
|
chartID,
|
|
arrowName,
|
|
subWindowID,
|
|
signal.time,
|
|
arrowPrice,
|
|
arrowCode,
|
|
arrowAnchorPoint,
|
|
arrowColor,
|
|
STYLE_SOLID,
|
|
3,
|
|
false,
|
|
false,
|
|
false,
|
|
0
|
|
);
|
|
//
|
|
// END Draw Signal Arrow ...
|
|
//
|
|
|
|
//
|
|
// START Draw Signal SL/TP ...
|
|
//
|
|
string slLineName = StringConcatenate(signalTag, "_SL_", signal.id);
|
|
string tpLineName = StringConcatenate(signalTag, "_TP_", signal.id);
|
|
|
|
//
|
|
color slColor = isLongSignal ? shortSignalColor : longSignalColor;
|
|
|
|
//
|
|
datetime time1 = iTime(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index + 1
|
|
);
|
|
|
|
//
|
|
// Draw Signal SL ...
|
|
result = DrawTrendLine(
|
|
chartID,
|
|
slLineName,
|
|
subWindowID,
|
|
time1,
|
|
signal.sl,
|
|
signal.time,
|
|
signal.sl,
|
|
slColor,
|
|
STYLE_SOLID,
|
|
2
|
|
);
|
|
|
|
//
|
|
// Draw Signal TP ...
|
|
result = DrawTrendLine(
|
|
chartID,
|
|
tpLineName,
|
|
subWindowID,
|
|
time1,
|
|
signal.tp,
|
|
signal.time,
|
|
signal.tp,
|
|
arrowColor,
|
|
STYLE_SOLID,
|
|
2
|
|
);
|
|
//
|
|
// END Draw Signal SL/TP ...
|
|
//
|
|
|
|
//
|
|
// Start Draw Signal Label ...
|
|
//
|
|
//
|
|
string labelName = StringConcatenate(signalTag, "_Label_", signal.id);
|
|
|
|
//
|
|
double labelPrice = isLongSignal ? arrowPrice - (positionThresholdFactor * _Point) : arrowPrice + (positionThresholdFactor * _Point);
|
|
|
|
//
|
|
string labelText = isLongSignal ? longSignalLabel : shortSignalLabel;
|
|
|
|
//
|
|
result = DrawText(
|
|
chartID,
|
|
labelName,
|
|
subWindowID,
|
|
signal.time,
|
|
labelPrice,
|
|
labelText,
|
|
"Arial",
|
|
10,
|
|
arrowColor,
|
|
0,
|
|
ANCHOR_CENTER
|
|
);
|
|
//
|
|
// End Draw Signal Label ...
|
|
//
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//
|
|
// End Signal Functions ...
|
|
//
|