721 lines
13 KiB
Plaintext
721 lines
13 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL4 XTPW Signal Global Library
|
|
// ---------------------------------------------------
|
|
// XSaherElm EA Signal Provider based on
|
|
// XTPow Indicator...
|
|
//
|
|
//
|
|
// 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 library ...
|
|
#include "../Libraries/x-saherelm.lib.mq4"
|
|
|
|
//
|
|
// Includes Indicator library ...
|
|
#include "../Libraries/x-saherelm.indicator.lib.mq4"
|
|
|
|
//
|
|
// Includes Models library ...
|
|
#include "../Libraries/x-saherelm.models.lib.mq4"
|
|
|
|
//
|
|
// START Inputs ...
|
|
//
|
|
//
|
|
input string xTPWStarter = "- XTPW Signal Provider -"; // ---> XTPW Signal Provider <---
|
|
|
|
//
|
|
input bool enableXTPWSignalling = true; // XTPW Signalling Enable
|
|
|
|
//
|
|
input double xTPWR2R = 2.5; // XTPW Risk To Reward Ratio
|
|
input int xTPWMaximumCandlesPerTrade = 206; // XTPW Maximum Candles which a Trade can open
|
|
|
|
//
|
|
input double xTPWPSarStep = 0.02; // XTPW Parabolic Sar Step
|
|
input double xTPWPSarMaximum = 0.2; // XTPW Parabolic Sar Maximum
|
|
|
|
//
|
|
input int xTPWSwingLength = 7; // XTPW Signal Swing Length
|
|
//
|
|
// END Inputs ...
|
|
//
|
|
|
|
//
|
|
// START Global Requirement Functions ...
|
|
//
|
|
//
|
|
// XTPW Based Signal Conditions ...
|
|
struct XTPWSignalConditions {
|
|
datetime startTime;
|
|
datetime signalTime;
|
|
datetime entryTime;
|
|
};
|
|
|
|
//
|
|
struct XTPWMarketState {
|
|
double psar;
|
|
double fast;
|
|
double slow;
|
|
double verifier;
|
|
};
|
|
|
|
//
|
|
static XTPWSignalConditions xTPWLongConds;
|
|
static bool xTPWCloseLongTrades = false;
|
|
static bool xTPWWaitForLongSignals = true;
|
|
|
|
//
|
|
static XTPWSignalConditions xTPWShortConds;
|
|
static bool xTPWCloseShortTrades = false;
|
|
static bool xTPWWaitForShortSignals = true;
|
|
//
|
|
// END Global Requirement Functions ...
|
|
//
|
|
|
|
//
|
|
// START Functions ...
|
|
//
|
|
//
|
|
// Check and Fill Long and Short Signal Handlers ...
|
|
void CheckXTPWSignalHandler(
|
|
const int bar_index
|
|
) {
|
|
//
|
|
// Check Market For Enable/Disable Signal Handlers ...
|
|
// Checking Market for Long Signals ...
|
|
|
|
//
|
|
if (!enableXTPWSignalling) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
datetime barTime = iTime(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
XOHCL candle = GetCandleModel(bar_index);
|
|
XOHCL pCandle = GetCandleModel(bar_index + 1);
|
|
}
|
|
|
|
//
|
|
// Check and Fill Long Signal Conditions ...
|
|
void CheckXTPWLongSignalConditions(
|
|
const int bar_index
|
|
) {
|
|
//
|
|
if (
|
|
!enableXTPWSignalling
|
|
|| !xTPWWaitForLongSignals
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
datetime barTime = iTime(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
bool startCondition = false;
|
|
bool signalCondition = false;
|
|
|
|
//
|
|
if (
|
|
startCondition
|
|
&& xTPWLongConds.startTime == 0
|
|
) {
|
|
//
|
|
xTPWLongConds.startTime = barTime;
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (
|
|
signalCondition
|
|
&& xTPWLongConds.startTime > 0
|
|
&& xTPWLongConds.signalTime == 0
|
|
) {
|
|
//
|
|
xTPWLongConds.signalTime = barTime;
|
|
xTPWLongConds.entryTime = barTime;
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check and Fill Short Signal Conditions ...
|
|
void CheckXShortSignalConditions(
|
|
const int bar_index
|
|
) {
|
|
//
|
|
if (
|
|
!enableXTPWSignalling
|
|
|| !xTPWWaitForShortSignals
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
datetime barTime = iTime(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
bool startCondition = false;
|
|
bool signalCondition = false;
|
|
|
|
//
|
|
if (
|
|
startCondition
|
|
&& xTPWShortConds.startTime == 0
|
|
) {
|
|
//
|
|
xTPWShortConds.startTime = barTime;
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (
|
|
signalCondition
|
|
&& xTPWShortConds.startTime > 0
|
|
&& xTPWShortConds.signalTime == 0
|
|
) {
|
|
//
|
|
xTPWShortConds.signalTime = barTime;
|
|
xTPWShortConds.entryTime = barTime;
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert Long Signal Conditions to XSignal ...
|
|
XSignalRequest GenerateXTPWSignal(
|
|
const ENUM_X_SIGNAL_TYPE type, // Signal Type ...
|
|
const string signalTag , // Signal Tag ...
|
|
const int bar_index
|
|
) {
|
|
//
|
|
XSignalRequest result = {};
|
|
|
|
//
|
|
result.hasSignal = false;
|
|
result.type = X_SIGNAL_NONE;
|
|
result.provider = X_UNKNOWN_PROVIDER;
|
|
|
|
//
|
|
if (!enableXTPWSignalling) {
|
|
return result;
|
|
}
|
|
|
|
|
|
//
|
|
bool requestLong = type == X_SIGNAL_LONG;
|
|
|
|
//
|
|
if (requestLong) {
|
|
//
|
|
if (
|
|
!ValidateXTPWLongConditions()
|
|
) {
|
|
return result;
|
|
}
|
|
} else {
|
|
//
|
|
if (
|
|
!ValidateXTPWShortConditions()
|
|
) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Price Calculations ...
|
|
//
|
|
RefreshRates();
|
|
|
|
//
|
|
double askPrice = SymbolInfoDouble(
|
|
_Symbol,
|
|
SYMBOL_ASK
|
|
);
|
|
|
|
//
|
|
double bidPrice = SymbolInfoDouble(
|
|
_Symbol,
|
|
SYMBOL_BID
|
|
);
|
|
|
|
//
|
|
double entryPrice = requestLong ?
|
|
askPrice :
|
|
bidPrice;
|
|
|
|
//
|
|
double exitPrice = requestLong ?
|
|
bidPrice :
|
|
askPrice;
|
|
|
|
//
|
|
double priceGap = MathAbs(entryPrice - exitPrice);
|
|
|
|
//
|
|
double ll =
|
|
//
|
|
GetMarketLowestLow(
|
|
bar_index,
|
|
xTPWSwingLength
|
|
)
|
|
;
|
|
|
|
//
|
|
double hh =
|
|
//
|
|
GetMarketHighestHigh(
|
|
bar_index,
|
|
xTPWSwingLength
|
|
)
|
|
;
|
|
|
|
//
|
|
double openPrice = iOpen(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
double closePrice = iClose(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
double risk = requestLong ?
|
|
MathMin(openPrice, closePrice) - ll :
|
|
hh - MathMax(openPrice, closePrice);
|
|
|
|
//
|
|
double reward = risk * xTPWR2R;
|
|
|
|
//
|
|
double sl = requestLong ?
|
|
0 :
|
|
0;
|
|
double tp = requestLong ?
|
|
entryPrice + reward :
|
|
entryPrice - reward
|
|
;
|
|
|
|
//
|
|
datetime barTime = iTime(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
result.signal.tp = tp;
|
|
result.signal.sl = sl;
|
|
result.signal.type = type;
|
|
result.signal.time = barTime;
|
|
result.signal.tag = signalTag;
|
|
result.signal.symbol = _Symbol;
|
|
result.signal.entry = entryPrice;
|
|
result.signal.id = totalSignals + 1;
|
|
result.signal.provider = X_XXX_PROVIDER;
|
|
|
|
//
|
|
result.hasSignal = true;
|
|
result.type = type;
|
|
result.provider = X_XXX_PROVIDER;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Signal Conditions ...
|
|
bool ValidateXTPWLongConditions() {
|
|
//
|
|
if (!enableXTPWSignalling) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
bool isConditionsFilled =
|
|
xTPWLongConds.startTime > 0
|
|
&& xTPWLongConds.signalTime > 0
|
|
&& xTPWLongConds.entryTime > 0
|
|
;
|
|
|
|
//
|
|
bool isBLFilled = false;
|
|
if (isConditionsFilled) {
|
|
//
|
|
int startBarIndex = iBarShift(
|
|
_Symbol,
|
|
_Period,
|
|
xTPWLongConds.startTime
|
|
);
|
|
|
|
//
|
|
int signalBarIndex = iBarShift(
|
|
_Symbol,
|
|
_Period,
|
|
xTPWLongConds.signalTime
|
|
);
|
|
|
|
//
|
|
int entryBarIndex = iBarShift(
|
|
_Symbol,
|
|
_Period,
|
|
xTPWLongConds.entryTime
|
|
);
|
|
|
|
//
|
|
isBLFilled =
|
|
//
|
|
xTPWLongConds.signalTime > xTPWLongConds.startTime
|
|
&& xTPWLongConds.entryTime >= xTPWLongConds.signalTime
|
|
;
|
|
}
|
|
|
|
//
|
|
bool result =
|
|
isBLFilled
|
|
&& isConditionsFilled
|
|
&& xTPWWaitForLongSignals
|
|
;
|
|
|
|
//
|
|
// Since maybe Conditions Filled but
|
|
// Slope is Negative, for Handling Next Signals and
|
|
// Prevent from infinity loop, here we Clear Signal Conditions ...
|
|
if (
|
|
!result
|
|
&& isConditionsFilled
|
|
) {
|
|
ClearXTPWLongSignalConditions();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Signal Conditions ...
|
|
bool ValidateXTPWShortConditions() {
|
|
//
|
|
if (!enableXTPWSignalling) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
bool isConditionsFilled =
|
|
xTPWShortConds.startTime > 0
|
|
&& xTPWShortConds.signalTime > 0
|
|
&& xTPWShortConds.entryTime > 0
|
|
;
|
|
|
|
//
|
|
bool isBLFilled = false;
|
|
if (isConditionsFilled) {
|
|
//
|
|
int startBarIndex = iBarShift(
|
|
_Symbol,
|
|
_Period,
|
|
xTPWShortConds.startTime
|
|
);
|
|
|
|
//
|
|
int signalBarIndex = iBarShift(
|
|
_Symbol,
|
|
_Period,
|
|
xTPWShortConds.signalTime
|
|
);
|
|
|
|
//
|
|
int entryBarIndex = iBarShift(
|
|
_Symbol,
|
|
_Period,
|
|
xTPWShortConds.entryTime
|
|
);
|
|
|
|
//
|
|
isBLFilled =
|
|
//
|
|
xTPWShortConds.signalTime > xTPWShortConds.startTime
|
|
&& xTPWShortConds.entryTime >= xTPWShortConds.signalTime
|
|
;
|
|
}
|
|
|
|
//
|
|
bool result =
|
|
isBLFilled
|
|
&& isConditionsFilled
|
|
&& xTPWWaitForShortSignals
|
|
;
|
|
|
|
//
|
|
// Since maybe Conditions Filled but
|
|
// Slope is Negative, for Handling Next Signals and
|
|
// Prevent from infinity loop, here we Clear Signal Conditions ...
|
|
if (
|
|
!result
|
|
&& isConditionsFilled
|
|
) {
|
|
ClearXTPWShortSignalConditions();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Clear Long Signal Conditions for New One ...
|
|
void ClearXTPWLongSignalConditions() {
|
|
//
|
|
xTPWLongConds.startTime = 0;
|
|
xTPWLongConds.entryTime = 0;
|
|
xTPWLongConds.signalTime = 0;
|
|
}
|
|
|
|
//
|
|
// Clear Short Signal Conditions for New One ...
|
|
void ClearXTPWShortSignalConditions() {
|
|
//
|
|
xTPWShortConds.startTime = 0;
|
|
xTPWShortConds.entryTime = 0;
|
|
xTPWShortConds.signalTime = 0;
|
|
}
|
|
|
|
//
|
|
// Check State for Long Signals ...
|
|
bool IsReadyForXTPWSignals(
|
|
const XSignal &signal
|
|
) {
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (!enableXTPWSignalling) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int signalBarIndex = iBarShift(
|
|
_Symbol,
|
|
_Period,
|
|
signal.time
|
|
);
|
|
|
|
//
|
|
// XOHCL candle = GetCandleModel(0);
|
|
XOHCL candle = GetCandleModel(signalBarIndex);
|
|
XOHCL pCandle = GetCandleModel(signalBarIndex + 1);
|
|
|
|
//
|
|
// Retrive XMarket States ...
|
|
|
|
//
|
|
double hh = GetMarketHighestHigh(
|
|
signalBarIndex,
|
|
xTPWSwingLength
|
|
);
|
|
double ll = GetMarketLowestLow(
|
|
signalBarIndex,
|
|
xTPWSwingLength
|
|
);
|
|
double diffChange = (hh - ll);
|
|
bool isBigSharpOccured =
|
|
diffChange > (600 * _Point)
|
|
;
|
|
|
|
//
|
|
bool isPSarVerified = false;
|
|
bool isTPowVerified = false;
|
|
bool isStateVerified = false;
|
|
bool isPriceVerified = false;
|
|
|
|
//
|
|
// Verify Long Signals ...
|
|
if (signal.type == X_SIGNAL_LONG) {
|
|
//
|
|
// Get Price Verification for Long ...
|
|
isPriceVerified =
|
|
//
|
|
// Starter ...
|
|
true
|
|
;
|
|
|
|
//
|
|
isTPowVerified =
|
|
//
|
|
// Starter ...
|
|
true
|
|
;
|
|
|
|
//
|
|
isPSarVerified =
|
|
//
|
|
// Starter ...
|
|
true
|
|
;
|
|
|
|
//
|
|
isStateVerified =
|
|
//
|
|
// Start ...
|
|
true
|
|
;
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Starter ...
|
|
true
|
|
//
|
|
&& isPSarVerified
|
|
//
|
|
&& isTPowVerified
|
|
//
|
|
&& isStateVerified
|
|
//
|
|
&& isPriceVerified
|
|
;
|
|
} else
|
|
//
|
|
// Verify Short Signals ...
|
|
if (signal.type == X_SIGNAL_SHORT) {
|
|
//
|
|
isPSarVerified =
|
|
//
|
|
// Starter ...
|
|
true
|
|
;
|
|
|
|
//
|
|
// Get Price Verification for Short ...
|
|
isPriceVerified =
|
|
//
|
|
// Starter ...
|
|
true
|
|
;
|
|
|
|
//
|
|
isTPowVerified =
|
|
//
|
|
// Starter ...
|
|
true
|
|
;
|
|
|
|
//
|
|
isStateVerified =
|
|
//
|
|
// Start ...
|
|
true
|
|
;
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Starter Condition ...
|
|
true
|
|
//
|
|
&& isPSarVerified
|
|
//
|
|
&& isTPowVerified
|
|
//
|
|
&& isStateVerified
|
|
//
|
|
&& isPriceVerified
|
|
;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//
|
|
// END Functions ...
|
|
//
|
|
|
|
//
|
|
// START Data Provider ...
|
|
//
|
|
XTPWMarketState GetXMTPWarketState(
|
|
const int bar_index
|
|
) {
|
|
//
|
|
XTPWMarketState result = {};
|
|
|
|
//
|
|
double fast = GetMA(
|
|
bar_index,
|
|
xTPWSwingLength,
|
|
0,
|
|
MODE_SMA,
|
|
PRICE_CLOSE
|
|
);
|
|
|
|
//
|
|
double slow = GetMA(
|
|
bar_index,
|
|
xTPWSwingLength * 2,
|
|
0,
|
|
MODE_SMA,
|
|
PRICE_CLOSE
|
|
);
|
|
|
|
//
|
|
int dailyCount = GetDailyCandleCount();
|
|
double verifier = GetMA(
|
|
bar_index,
|
|
dailyCount,
|
|
0,
|
|
MODE_EMA,
|
|
PRICE_MEDIAN
|
|
);
|
|
|
|
//
|
|
double psar = iSAR(
|
|
_Symbol,
|
|
_Period,
|
|
xTPWPSarStep,
|
|
xTPWPSarMaximum,
|
|
bar_index
|
|
);
|
|
|
|
//
|
|
result.psar = psar;
|
|
result.fast = fast;
|
|
result.slow = slow;
|
|
result.verifier = verifier;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//
|
|
// END Data Provider ...
|
|
//
|