602 lines
24 KiB
Plaintext
602 lines
24 KiB
Plaintext
|
|
//
|
|
// In Profit ...
|
|
// When a Position running in Profit, we have to look pressures by Same Direction
|
|
// of Main Position. for eaxmple if it is long, we look for Bullish Pressures and
|
|
// if it is short we look for Bearish Pressures.
|
|
// when pressure happens we must Trail position Stop ...
|
|
if (isInProfit)
|
|
{
|
|
//
|
|
// Do In Profit Protection Mechanism ...
|
|
|
|
//
|
|
// Trail Stops ...
|
|
// Remove Trailed Positions TP ...
|
|
bool allowTrailStop = AllowTrailStopInProfits();
|
|
double trailStep = TrailStopStepsInPoint();
|
|
bool allowOnlyUnprotecteds = OnlyTrailUnprotectedPositions();
|
|
bool isProtectionTrailPassed = !allowOnlyUnprotecteds
|
|
? true
|
|
: supportsCount == 0;
|
|
if (allowTrailStop && trailStep > 0 && isProtectionTrailPassed)
|
|
{
|
|
//
|
|
// Temp Vaiables ...
|
|
bool canTrailStop = false;
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
//
|
|
// Check Conditions ...
|
|
canTrailStop = isTicksBullishForLong &&
|
|
hasBullishConditions;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Check Conditions ...
|
|
canTrailStop = isTicksBearishForShort &&
|
|
hasBearishConditions;
|
|
}
|
|
|
|
//
|
|
// Do Stop Trailling ...
|
|
if (canTrailStop)
|
|
{
|
|
//
|
|
int lastTrailedStep = mData[iDX].trailStep;
|
|
|
|
//
|
|
double entry = position.entry;
|
|
double pointValue = position.GetPointsValue();
|
|
double profitInPoint = position.GetProfitInPoint();
|
|
|
|
//
|
|
double requiredProfit =
|
|
lastTrailedStep == 0
|
|
? ProtectorStartDistanceInPoint()
|
|
: ProtectorStartDistanceInPoint() + (lastTrailedStep * trailStep);
|
|
|
|
//
|
|
bool isProfitsPassed = profitInPoint > requiredProfit;
|
|
if (isProfitsPassed)
|
|
{
|
|
//
|
|
double delta = (requiredProfit * pointValue);
|
|
|
|
//
|
|
double sl =
|
|
isLong
|
|
? entry + delta
|
|
: entry - delta;
|
|
|
|
//
|
|
string comment = "EQM Trail Stop ...";
|
|
|
|
//
|
|
// Try to Modify Position ...
|
|
result = mTrader.Modify(
|
|
position.ticket,
|
|
sl,
|
|
position.tp,
|
|
comment //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
mData[iDX].trailStep++;
|
|
|
|
//
|
|
string message = "EQM Trail (" + ToString(position.ticket) + ") Stop ...";
|
|
Alert(message);
|
|
|
|
//
|
|
XPosition trailedPosition;
|
|
bool hasPosition = mTrader.GetPosition(
|
|
position.ticket,
|
|
trailedPosition //
|
|
);
|
|
|
|
//
|
|
// Check Remove Trailed Positions TP Conditions ...
|
|
int removeTPOnTrailStep = RmoveTPOnTrailStep();
|
|
if (removeTPOnTrailStep > 0 && mData[iDX].trailStep == removeTPOnTrailStep && trailedPosition.tp != 0)
|
|
{
|
|
//
|
|
string comment = "EQM Removes TP ...";
|
|
|
|
//
|
|
// Remove Position's TP ...
|
|
result = mTrader.Modify(
|
|
trailedPosition.ticket,
|
|
trailedPosition.sl,
|
|
0,
|
|
comment //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
string message = "EQM Removes (" + ToString(trailedPosition.ticket) + ") TP ...";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
bool allowRecover = AllowRecoverInDrawdowns();
|
|
double volumeMultiplier = RecoveryMultiplier();
|
|
if (allowRecover && !canFreeze && volumeMultiplier > 0 && supportsCount > 0)
|
|
{
|
|
//
|
|
bool canRecover = false;
|
|
int delayMinutes = RecoveryDelayInMinute();
|
|
double recoveryDistancePoint = RecoveryDistanceInPoint();
|
|
|
|
//
|
|
// Temparory Requirement for Recover Signal ...
|
|
double sl = 0;
|
|
double tp = 0;
|
|
double entry = 0;
|
|
ENUM_POSITION_TYPE type = NULL;
|
|
ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET;
|
|
double lastStep = mData[iDX].protectionStep;
|
|
double volume = position.volume * volumeMultiplier;
|
|
bool applyLevel = ApplyRecoveryLevelOnVolume();
|
|
if (applyLevel)
|
|
{
|
|
//
|
|
volume = supportsCount <= 0
|
|
? position.volume * volumeMultiplier
|
|
: position.volume * ((supportsCount + 1) * volumeMultiplier);
|
|
}
|
|
|
|
//
|
|
datetime currentTime = TimeCurrent();
|
|
double currentProfit = position.GetProfitInPoint();
|
|
datetime lastProtectedOn = mData[iDX].lastProtectedOn;
|
|
double lastProtectedProfit = mData[iDX].lastProtectedInProfit;
|
|
bool isRecoveryConditionsPassed =
|
|
//
|
|
// Check Regular Conditions ...
|
|
delayMinutes > 0 &&
|
|
recoveryDistancePoint > 0 &&
|
|
IsValid(lastProtectedOn) &&
|
|
//
|
|
// Check Time Delay Passed ...
|
|
(TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) >= ulong(delayMinutes * 60) &&
|
|
//
|
|
// Check Recovery Distance Passed ...
|
|
MathAbs(currentProfit) - MathAbs(lastProtectedProfit) >= recoveryDistancePoint;
|
|
|
|
//
|
|
if (isRecoveryConditionsPassed)
|
|
{
|
|
//
|
|
// Long Recovery ...
|
|
if (isLong)
|
|
{
|
|
//
|
|
// Same Direction ...
|
|
canRecover =
|
|
//
|
|
isTicksBullishForLong &&
|
|
hasBullishTrend &&
|
|
(hasBullishPower ||
|
|
hasBullishPattern ||
|
|
hasBullishPressure)
|
|
//
|
|
;
|
|
if (canRecover)
|
|
{
|
|
//
|
|
sl = position.sl;
|
|
tp = position.tp;
|
|
type = POSITION_TYPE_BUY;
|
|
}
|
|
}
|
|
//
|
|
// Short Recovery ...
|
|
else
|
|
{
|
|
//
|
|
// Same Direction ...
|
|
canRecover =
|
|
//
|
|
isTicksBearishForShort &&
|
|
hasBearishTrend &&
|
|
(hasBearishPower ||
|
|
hasBearishPattern ||
|
|
hasBearishPressure)
|
|
//
|
|
;
|
|
if (canRecover)
|
|
{
|
|
//
|
|
sl = position.sl;
|
|
tp = position.tp;
|
|
type = POSITION_TYPE_SELL;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (canRecover)
|
|
{
|
|
//
|
|
XSignal signal;
|
|
entry = GetEntry(
|
|
position.symbol,
|
|
type //
|
|
);
|
|
|
|
//
|
|
// Prepare Signal ...
|
|
result = signal.Prepare(
|
|
position.symbol,
|
|
position.provider,
|
|
position.period,
|
|
type,
|
|
mode,
|
|
entry,
|
|
volume,
|
|
sl,
|
|
tp //
|
|
);
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
// Generate Comment for Recover and Support ...
|
|
string comment = GenerateSupportTag(position.ticket);
|
|
|
|
//
|
|
signal.comment = comment;
|
|
|
|
//
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT state;
|
|
result = ExecuteSignal(
|
|
signal,
|
|
state,
|
|
true // Support Signal need to Ignore Policies ...
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
mData[iDX].protectionStep++;
|
|
mData[iDX].lastProtectedOn = currentTime;
|
|
mData[iDX].lastProtectedInProfit = currentProfit;
|
|
|
|
//
|
|
string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Recovery Position in Level: " +
|
|
ToString(lastStep + 1) +
|
|
" for (" + ToString(position.ticket) + ")";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Points of Profit and Do Partial Closing ...
|
|
double partialCloseVolume = PartialCloseVolumeInProfit();
|
|
double partialCloseProfitPoint = PartialCloseOnSpecificPointOfProfit();
|
|
if (partialCloseVolume > 0 && partialCloseProfitPoint > 0)
|
|
{
|
|
//
|
|
double profitPoints = position.GetProfitInPoint();
|
|
if (profitPoints >= partialCloseProfitPoint && !mData[iDX].partiallyClosed)
|
|
{
|
|
//
|
|
string comment = "EQM Partial Close ...";
|
|
|
|
//
|
|
// Do Partial Closing ...
|
|
result = mTrader.ClosePartial(
|
|
position.ticket,
|
|
partialCloseVolume,
|
|
comment //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
mData[iDX].partiallyClosed = true;
|
|
|
|
//
|
|
string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ")";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// In Drawdown ...
|
|
// When a Position running in Drawdown, we have to look for pressures by Indirection
|
|
// of Main Position. for example if it is long, we Look For Bearish Pressures and if
|
|
// it is short we Look for Bullish Pressure.
|
|
// when indirectional pressure found we must Open a Recovery Position.
|
|
// also if Same Direction Pressure Found we try to Recover Same Direction using Grid ...
|
|
else
|
|
{
|
|
//
|
|
bool allowRecover = AllowRecoverInDrawdowns();
|
|
double volumeMultiplier = RecoveryMultiplier();
|
|
if (allowRecover && !canFreeze && volumeMultiplier > 0)
|
|
{
|
|
//
|
|
bool canRecover = false;
|
|
int delayMinutes = RecoveryDelayInMinute();
|
|
double recoveryDistancePoint = RecoveryDistanceInPoint();
|
|
|
|
//
|
|
// Temparory Requirement for Recover Signal ...
|
|
double sl = 0;
|
|
double tp = 0;
|
|
double entry = 0;
|
|
ENUM_POSITION_TYPE type = NULL;
|
|
ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET;
|
|
double lastStep = mData[iDX].protectionStep;
|
|
double volume = position.volume * volumeMultiplier;
|
|
bool applyLevel = ApplyRecoveryLevelOnVolume();
|
|
if (applyLevel)
|
|
{
|
|
//
|
|
volume = supportsCount <= 0
|
|
? position.volume * volumeMultiplier
|
|
: position.volume * ((supportsCount + 1) * volumeMultiplier);
|
|
}
|
|
|
|
//
|
|
datetime currentTime = TimeCurrent();
|
|
double currentDrawdown = position.GetProfitInPoint();
|
|
datetime lastProtectedOn = mData[iDX].lastProtectedOn;
|
|
double lastProtectedDrawdown = mData[iDX].lastProtectedInDrawdown;
|
|
bool isRecoveryConditionsPassed = supportsCount <= 0
|
|
? true
|
|
:
|
|
//
|
|
// Check Regular Conditions ...
|
|
delayMinutes > 0 &&
|
|
recoveryDistancePoint > 0 &&
|
|
IsValid(lastProtectedOn) &&
|
|
lastProtectedDrawdown < 0 &&
|
|
//
|
|
// Check Time Delay Passed ...
|
|
(TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) >= ulong(delayMinutes * 60) &&
|
|
//
|
|
// Check Recovery Distance Passed ...
|
|
MathAbs(currentDrawdown) - MathAbs(lastProtectedDrawdown) >= recoveryDistancePoint;
|
|
|
|
//
|
|
if (isRecoveryConditionsPassed)
|
|
{
|
|
//
|
|
// Long Recovery ...
|
|
if (isLong)
|
|
{
|
|
//
|
|
// Opposit Direction ...
|
|
canRecover =
|
|
//
|
|
isTicksBearishForShort &&
|
|
hasBearishTrend &&
|
|
(hasBearishPower ||
|
|
hasBearishPattern ||
|
|
hasBearishPressure)
|
|
//
|
|
;
|
|
if (canRecover)
|
|
{
|
|
//
|
|
sl = position.tp;
|
|
tp = position.sl;
|
|
type = POSITION_TYPE_SELL;
|
|
}
|
|
}
|
|
//
|
|
// Short Recovery ...
|
|
else
|
|
{
|
|
//
|
|
// Opposit Direction ...
|
|
canRecover =
|
|
//
|
|
isTicksBullishForLong &&
|
|
hasBullishTrend &&
|
|
(hasBullishPower ||
|
|
hasBullishPattern ||
|
|
hasBullishPressure)
|
|
//
|
|
;
|
|
if (canRecover)
|
|
{
|
|
//
|
|
sl = position.tp;
|
|
tp = position.sl;
|
|
type = POSITION_TYPE_BUY;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (canRecover)
|
|
{
|
|
//
|
|
XSignal signal;
|
|
entry = GetEntry(
|
|
position.symbol,
|
|
type //
|
|
);
|
|
|
|
//
|
|
// Prepare Signal ...
|
|
result = signal.Prepare(
|
|
position.symbol,
|
|
position.provider,
|
|
position.period,
|
|
type,
|
|
mode,
|
|
entry,
|
|
volume,
|
|
sl,
|
|
tp //
|
|
);
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
// Generate Comment for Recover and Support ...
|
|
string comment = GenerateSupportTag(position.ticket);
|
|
|
|
//
|
|
signal.comment = comment;
|
|
|
|
//
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT state;
|
|
result = ExecuteSignal(
|
|
signal,
|
|
state,
|
|
true // Support Signal need to Ignore Policies ...
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
mData[iDX].protectionStep++;
|
|
mData[iDX].lastProtectedOn = currentTime;
|
|
mData[iDX].lastProtectedInDrawdown = currentDrawdown;
|
|
|
|
//
|
|
string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Recovery Position in Level: " +
|
|
ToString(lastStep + 1) +
|
|
" for (" + ToString(position.ticket) + ")";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
if (canFreeze &&
|
|
supportsCount <= 0 &&
|
|
position.profit < 0 &&
|
|
!mData[iDX].freezed &&
|
|
MathAbs(profitInPoint) >= freezePoint)
|
|
{
|
|
//
|
|
bool removeTPSL = RemoveFreezedPositionsTPSL();
|
|
//
|
|
// Temparory Requirement for Recover Signal ...
|
|
double sl = removeTPSL ? 0 : position.tp;
|
|
double tp = removeTPSL ? 0 : position.sl;
|
|
ENUM_POSITION_TYPE type = isLong
|
|
? POSITION_TYPE_SELL
|
|
: POSITION_TYPE_BUY;
|
|
double entry = GetEntry(
|
|
position.symbol,
|
|
type //
|
|
);
|
|
ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET;
|
|
double volume = position.volume * freezeVolumeMultiplier;
|
|
|
|
//
|
|
XSignal signal;
|
|
|
|
//
|
|
// Prepare Signal ...
|
|
result = signal.Prepare(
|
|
position.symbol,
|
|
position.provider,
|
|
position.period,
|
|
type,
|
|
mode,
|
|
entry,
|
|
volume,
|
|
sl,
|
|
tp //
|
|
);
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
// Generate Comment for Recover and Support ...
|
|
string comment = GenerateSupportTag(position.ticket);
|
|
|
|
//
|
|
signal.comment = comment;
|
|
|
|
//
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT state;
|
|
result = ExecuteSignal(
|
|
signal,
|
|
state,
|
|
true // Support Signal need to Ignore Policies ...
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
mData[iDX].freezed = true;
|
|
|
|
//
|
|
string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Freeze Position for (" + ToString(position.ticket) + ")";
|
|
Alert(message);
|
|
|
|
//
|
|
string comment = "EQM Removes Freezed TP/SL ...";
|
|
result = mTrader.Modify(
|
|
position.ticket,
|
|
0,
|
|
0,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
string message = "EQM Remove Freezed Position (" + ToString(position.ticket) + ") TP/SL ..";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Points of Drawdown and Do Partial Closing ...
|
|
double partialCloseVolume = PartialCloseVolumeInDrawdown();
|
|
double partialCloseDrawdownPoint = PartialCloseOnSpecificPointOfDrawdown();
|
|
if (partialCloseVolume > 0 && partialCloseDrawdownPoint > 0)
|
|
{
|
|
//
|
|
double profitPoints = position.GetProfitInPoint();
|
|
if (profitPoints < 0 && MathAbs(profitPoints) >= partialCloseDrawdownPoint && !mData[iDX].partiallyClosed)
|
|
{
|
|
//
|
|
string comment = "EQM Partial Close ...";
|
|
|
|
//
|
|
// Do Partial Closing ...
|
|
result = mTrader.ClosePartial(
|
|
position.ticket,
|
|
partialCloseVolume,
|
|
comment //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
mData[iDX].partiallyClosed = true;
|
|
|
|
//
|
|
string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ")";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|