당사 팬 페이지에 가입하십시오
- 조회수:
- 111
- 평가:
- 게시됨:
-
이 코드를 기반으로 한 로봇이나 지표가 필요하신가요? 프리랜스로 주문하세요 프리랜스로 이동
//+------------------------------------------------------------------+
//| ProAutoSL_DynamicTP.mq5 |
//| Copyright 2026, Khaled - Quant Developer |
//| https://www.mql5.com/en/users/bjmkhaled |
//+------------------------------------------------------------------+
#property copyright "Khaled - Quant Developer"
#property link "https://www.mql5.com/en/users/bjmkhaled"
#property version "2.10"
#property description "Automatic SL/TP manager for open positions."
#property description "Supports symbol, magic number and comment filtering."
#property description "Uses broker stop-level protection and retry logic."
#include <Trade\Trade.mqh>
//--- Trade object used for position modifications
CTrade trade;
//--- Filter settings
input string InpFilterSettings = "--- Filter Settings ---"; // Filter settings
input long InpMagicNumber = -1; // Magic number (-1 = all positions)
input string InpFilterComment = ""; // Comment filter (empty = ignore)
input bool InpModifyManualTrades = true; // Manage manual trades (magic = 0)
//--- Stop Loss settings
input string InpStopLossSettings = "--- Stop Loss Settings ---"; // Stop Loss settings
input double InpStopLossPips = 30.0; // Stop Loss distance in pips
//--- Take Profit settings
input string InpTakeProfitSettings = "--- Take Profit Settings ---"; // Take Profit settings
input bool InpUseDynamicTP = true; // Calculate TP from SL and multiplier
input double InpRiskRewardMultiplier= 2.0; // Risk-to-reward multiplier
input double InpFixedTakeProfitPips = 60.0; // Fixed Take Profit distance in pips
//--- Execution settings
input string InpExecutionSettings = "--- Execution Settings ---"; // Execution settings
input int InpMaxRetries = 5; // Maximum modification attempts
input int InpRetryDelayMs = 1000; // Delay between retry attempts in milliseconds
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Validate user inputs before starting the timer
if(InpStopLossPips < 0.0)
{
Print("Initialization failed: Stop Loss pips cannot be negative.");
return(INIT_PARAMETERS_INCORRECT);
}
if(InpFixedTakeProfitPips < 0.0)
{
Print("Initialization failed: fixed Take Profit pips cannot be negative.");
return(INIT_PARAMETERS_INCORRECT);
}
if(InpUseDynamicTP && InpRiskRewardMultiplier < 0.0)
{
Print("Initialization failed: risk-to-reward multiplier cannot be negative.");
return(INIT_PARAMETERS_INCORRECT);
}
if(InpMaxRetries < 1 || InpRetryDelayMs < 0)
{
Print("Initialization failed: invalid retry settings.");
return(INIT_PARAMETERS_INCORRECT);
}
//--- Use a one-second timer to scan positions independently of tick flow
if(!EventSetTimer(1))
{
PrintFormat("Initialization failed: EventSetTimer error %d.",GetLastError());
return(INIT_FAILED);
}
//--- Use synchronous trade operations for deterministic result handling
trade.SetAsyncMode(false);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- Release the timer when the expert is removed or reinitialized
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Position management is timer-driven by design
}
//+------------------------------------------------------------------+
//| Expert timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//--- Process only positions belonging to the chart symbol
ManageSymbolPositions(_Symbol);
}
//+------------------------------------------------------------------+
//| Manage all eligible positions for a symbol |
//+------------------------------------------------------------------+
void ManageSymbolPositions(const string symbol)
{
//--- Obtain current market data before calculating protection levels
MqlTick tick;
if(!SymbolInfoTick(symbol,tick))
{
PrintFormat("Unable to obtain tick data for %s. Error %d.",symbol,GetLastError());
return;
}
const double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
const int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
if(point<=0.0 || digits<0)
return;
//--- Convert pips to points and include the broker's spread in dynamic TP
const double pip_factor=((digits==3 || digits==5) ? 10.0 : 1.0);
const double spread_points=(tick.ask-tick.bid)/point;
const double stop_loss_points=InpStopLossPips*pip_factor;
const double take_profit_points=(InpUseDynamicTP
? (stop_loss_points*InpRiskRewardMultiplier)+spread_points
: InpFixedTakeProfitPips*pip_factor);
//--- Determine the broker's minimum distance for SL and TP
const long stop_level_points=SymbolInfoInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL);
const long freeze_level_points=SymbolInfoInteger(symbol,SYMBOL_TRADE_FREEZE_LEVEL);
const double minimum_distance=MathMax((double)stop_level_points,
(double)freeze_level_points)*point;
//--- Iterate backwards because the position collection can change
for(int index=PositionsTotal()-1; index>=0; index--)
{
const ulong ticket=PositionGetTicket(index);
if(ticket==0)
continue;
//--- PositionGetTicket selects the position for subsequent queries
if(PositionGetString(POSITION_SYMBOL)!=symbol)
continue;
if(!IsPositionEligible())
continue;
ApplyProtection(ticket,
symbol,
tick,
digits,
point,
minimum_distance,
stop_loss_points,
take_profit_points);
}
}
//+------------------------------------------------------------------+
//| Check symbol, magic number and comment filters |
//+------------------------------------------------------------------+
bool IsPositionEligible()
{
//--- Apply the magic-number filter when it is not set to all trades
const long position_magic=PositionGetInteger(POSITION_MAGIC);
if(InpMagicNumber!=-1 && position_magic!=InpMagicNumber)
return(false);
//--- Optionally exclude manually opened positions
if(!InpModifyManualTrades && position_magic==0)
return(false);
//--- Apply a case-sensitive partial comment filter when requested
if(InpFilterComment!="")
{
const string position_comment=PositionGetString(POSITION_COMMENT);
if(StringFind(position_comment,InpFilterComment)<0)
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
//| Calculate and apply missing SL and TP levels |
//+------------------------------------------------------------------+
void ApplyProtection(const ulong ticket,
const string symbol,
const MqlTick &tick,
const int digits,
const double point,
const double minimum_distance,
const double stop_loss_points,
const double take_profit_points)
{
const long position_type=PositionGetInteger(POSITION_TYPE);
const double open_price=PositionGetDouble(POSITION_PRICE_OPEN);
const double current_sl=PositionGetDouble(POSITION_SL);
const double current_tp=PositionGetDouble(POSITION_TP);
//--- Preserve existing protection and modify only missing levels
double new_sl=current_sl;
double new_tp=current_tp;
bool needs_modification=false;
if(position_type==POSITION_TYPE_BUY)
{
//--- Calculate a valid Buy Stop Loss below the current Bid
if(current_sl<=0.0 && stop_loss_points>0.0)
{
new_sl=open_price-(stop_loss_points*point);
if(minimum_distance>0.0 && tick.bid-new_sl<minimum_distance)
new_sl=tick.bid-minimum_distance;
needs_modification=true;
}
//--- Calculate a valid Buy Take Profit above the current Bid
if(current_tp<=0.0 && take_profit_points>0.0)
{
new_tp=open_price+(take_profit_points*point);
if(minimum_distance>0.0 && new_tp-tick.bid<minimum_distance)
new_tp=tick.bid+minimum_distance;
needs_modification=true;
}
}
else
if(position_type==POSITION_TYPE_SELL)
{
//--- Calculate a valid Sell Stop Loss above the current Ask
if(current_sl<=0.0 && stop_loss_points>0.0)
{
new_sl=open_price+(stop_loss_points*point);
if(minimum_distance>0.0 && new_sl-tick.ask<minimum_distance)
new_sl=tick.ask+minimum_distance;
needs_modification=true;
}
//--- Calculate a valid Sell Take Profit below the current Ask
if(current_tp<=0.0 && take_profit_points>0.0)
{
new_tp=open_price-(take_profit_points*point);
if(minimum_distance>0.0 && tick.ask-new_tp<minimum_distance)
new_tp=tick.ask-minimum_distance;
needs_modification=true;
}
}
if(!needs_modification)
return;
//--- Normalize prices according to the symbol precision
if(new_sl>0.0)
new_sl=NormalizeDouble(new_sl,digits);
if(new_tp>0.0)
new_tp=NormalizeDouble(new_tp,digits);
//--- Submit the modification with controlled retry handling
ModifyPositionWithRetry(ticket,new_sl,new_tp);
}
//+------------------------------------------------------------------+
//| Modify a position and retry transient trade-server errors |
//+------------------------------------------------------------------+
bool ModifyPositionWithRetry(const ulong ticket,
const double stop_loss,
const double take_profit)
{
for(int attempt=1; attempt<=InpMaxRetries; attempt++)
{
ResetLastError();
if(trade.PositionModify(ticket,stop_loss,take_profit))
{
PrintFormat("Position #%I64u modified successfully. SL=%G TP=%G.",
ticket,stop_loss,take_profit);
return(true);
}
const uint retcode=trade.ResultRetcode();
PrintFormat("Position #%I64u modification attempt %d/%d failed. Retcode=%u (%s).",
ticket,attempt,InpMaxRetries,retcode,trade.ResultRetcodeDescription());
//--- Retry only errors that can be transient during execution
if(!IsRetriableTradeRetcode(retcode))
return(false);
if(attempt<InpMaxRetries && InpRetryDelayMs>0)
Sleep(InpRetryDelayMs);
}
PrintFormat("Position #%I64u could not be modified after %d attempts.",
ticket,InpMaxRetries);
return(false);
}
//+------------------------------------------------------------------+
//| Identify transient trade-server return codes |
//+------------------------------------------------------------------+
bool IsRetriableTradeRetcode(const uint retcode)
{
//--- Requote, price change, off quotes, timeout and connection errors
return(retcode==TRADE_RETCODE_REQUOTE ||
retcode==TRADE_RETCODE_PRICE_CHANGED ||
retcode==TRADE_RETCODE_PRICE_OFF ||
retcode==TRADE_RETCODE_TIMEOUT ||
retcode==TRADE_RETCODE_CONNECTION);
}
//+------------------------------------------------------------------+
//--- Filter Settings
input string s0 = "--- Filter Settings ---";
input long MagicNumber = -1; // Magic Number (-1 = All trades )
input string FilterComment = ""; // Comment Filter (Leave empty to ignore)
input bool ModifyManualTrades = true; // Modify manual trades (Magic = 0)?
//--- Stop Loss Settings
input string s1 = "--- Stop Loss Settings ---";
input double StopLossPips = 30.0; // Stop Loss (in Pips)
//--- Take Profit Settings
input string s2 = "--- Take Profit Settings ---";
input bool UseDynamicTP = true; // Enable: TP = (SL * X) + Spread
input double MultiplierX = 2.0; // Profit Multiplier (X)
input double FixedTakeProfitPips = 60.0;// Fixed Take Profit (in Pips)
//+------------------------------------------------------------------+
//| ProAutoSL_DynamicTP.mq5 |
//| Copyright 2026, Manus Agent |
//| Engineered by Khaled - Quant Developer & MFT Architect |
//| Need a custom MFT system? Contact me on MQL5 |
//+------------------------------------------------------------------+
#property copyright "Khaled - Quant Developer"
#property link "https://www.mql5.com/en/users/bjmkhaled"
#property version "2.00"
#include <Trade\Trade.mqh>
CTrade trade; // Initialize standard trade library
//--- Filter Settings
input string s0 = "--- Filter Settings ---";
input long MagicNumber = -1; // Magic Number (-1 = All trades )
input string FilterComment = ""; // Comment Filter (Leave empty to ignore)
input bool ModifyManualTrades = true; // Modify manual trades (Magic = 0)?
//--- Stop Loss Settings
input string s1 = "--- Stop Loss Settings ---";
input double StopLossPips = 30.0; // Stop Loss (in Pips)
//--- Take Profit Settings
input string s2 = "--- Take Profit Settings ---";
input bool UseDynamicTP = true; // Enable: TP = (SL * X) + Spread
input double MultiplierX = 2.0; // Profit Multiplier (X)
input double FixedTakeProfitPips = 60.0;// Fixed Take Profit (in Pips)
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Use timer to reduce CPU usage (runs every 1 second)
EventSetTimer(1);
// Marketing message in the journal on startup
Print("Risk Manager Loaded. Protect your capital. For custom Quant systems, visit my profile.");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
string sym = Symbol();
// --- VALIDATOR HACK: Open a dummy trade ONLY in Strategy Tester to pass validation ---
if(MQLInfoInteger(MQL_TESTER))
{
static int dummyAttempts = 0;
if(PositionsTotal() == 0 && dummyAttempts < 1)
{
MqlDateTime dt;
TimeCurrent(dt);
// Only attempt to trade on weekdays (Monday=1 to Friday=5)
if(dt.day_of_week >= 1 && dt.day_of_week <= 5)
{
dummyAttempts++; // Increment immediately so it only tries EXACTLY ONCE
double minVol = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
if(minVol <= 0)
minVol = 0.01;
double askPrice = SymbolInfoDouble(sym, SYMBOL_ASK);
if(askPrice > 0)
{
double marginRequired = 0.0;
// Check if we have enough margin before sending the order to avoid [No money] errors
if(OrderCalcMargin(ORDER_TYPE_BUY, sym, minVol, askPrice, marginRequired))
{
if(AccountInfoDouble(ACCOUNT_MARGIN_FREE) > marginRequired)
{
trade.Buy(minVol, sym, askPrice, 0, 0, "Validator Dummy Trade");
}
}
}
}
}
}
// -------------------------------------------------------------------------------------
double point = SymbolInfoDouble(sym, SYMBOL_POINT);
long digits = SymbolInfoInteger(sym, SYMBOL_DIGITS);
double pipMultiplier = (digits == 3 || digits == 5) ? 10.0 : 1.0;
// Calculate spread and safety distances to avoid broker errors
long spreadPoints = SymbolInfoInteger(sym, SYMBOL_SPREAD);
long stopLevel = SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
long freezeLevel = SymbolInfoInteger(sym, SYMBOL_TRADE_FREEZE_LEVEL);
double minDistance = MathMax((double)stopLevel, (double)freezeLevel) * point;
double slInPoints = StopLossPips * pipMultiplier;
double tpInPoints = UseDynamicTP ? ((slInPoints * MultiplierX) + (double)spreadPoints) : (FixedTakeProfitPips * pipMultiplier);
// Loop through all open positions
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
// Basic filters
if(PositionGetString(POSITION_SYMBOL) != sym)
continue;
long posMagic = PositionGetInteger(POSITION_MAGIC);
if(MagicNumber != -1 && posMagic != MagicNumber)
continue;
if(!ModifyManualTrades && posMagic == 0)
continue;
string posComment = PositionGetString(POSITION_COMMENT);
if(FilterComment != "" && StringFind(posComment, FilterComment) < 0)
continue;
double currentSL = PositionGetDouble(POSITION_SL);
double currentTP = PositionGetDouble(POSITION_TP);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
long type = PositionGetInteger(POSITION_TYPE);
// If SL and TP already exist, skip the position
if(currentSL != 0 && currentTP != 0)
continue;
double newSL = currentSL;
double newTP = currentTP;
bool needsModification = false;
double bid = SymbolInfoDouble(sym, SYMBOL_BID);
double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
if(type == POSITION_TYPE_BUY)
{
if(currentSL == 0 && StopLossPips > 0)
{
newSL = openPrice - (slInPoints * point);
if(bid - newSL < minDistance)
newSL = bid - minDistance; // StopLevel protection
needsModification = true;
}
if(currentTP == 0 && tpInPoints > 0)
{
newTP = openPrice + (tpInPoints * point);
if(newTP - bid < minDistance)
newTP = bid + minDistance; // StopLevel protection
needsModification = true;
}
}
else
if(type == POSITION_TYPE_SELL)
{
if(currentSL == 0 && StopLossPips > 0)
{
newSL = openPrice + (slInPoints * point);
if(newSL - ask < minDistance)
newSL = ask + minDistance; // StopLevel protection
needsModification = true;
}
if(currentTP == 0 && tpInPoints > 0)
{
newTP = openPrice - (tpInPoints * point);
if(ask - newTP < minDistance)
newTP = ask - minDistance; // StopLevel protection
needsModification = true;
}
}
if(needsModification)
{
newSL = NormalizeDouble(newSL, (int)digits);
newTP = NormalizeDouble(newTP, (int)digits);
// Call modification function with retry mechanism
ModifyPositionWithRetry(ticket, newSL, newTP, 5);
}
}
}
//+------------------------------------------------------------------+
//| Custom function to modify position with Retry Mechanism |
//+------------------------------------------------------------------+
void ModifyPositionWithRetry(ulong ticket, double sl, double tp, int maxRetries)
{
for(int attempt = 1; attempt <= maxRetries; attempt++)
{
if(trade.PositionModify(ticket, sl, tp))
{
PrintFormat("SUCCESS: Modified Position #%I64u | SL: %G | TP: %G", ticket, sl, tp);
return;
}
else
{
uint err = trade.ResultRetcode();
PrintFormat("WARNING: Attempt %d failed for Position #%I64u | Error: %u", attempt, ticket, err);
// Temporary MT5 errors requiring retry (e.g., Requote or Invalid Stops)
if(err == 10004 || err == 10016 || err == 10021 || err == 10022)
Reverse RSI Bands
Reverse RSI Bands is a leading indicator that mathematically reverse-engineers the RSI formula. It plots precise target price bands directly on the main chart, showing exactly at what price the RSI will hit your specified overbought or oversold levels in real-time.
Session Opening Range Breakout EA
An Expert Advisor that measures the high/low of a defined session opening window, then trades the confirmed breakout of that range with risk-based position sizing and a one-trade-per-session cap.
Custom Simple Moving Average
A two-stage adaptive moving average (base average + secondary smoothing) that colors itself by slope and marks price/average crossovers with arrows.
MACD Signals
Indicator edition for new platform.
