OPEN-SOURCE SCRIPT

My script

//+------------------------------------------------------------------+
//| Expert.mq5 |
//| Copyright 2023, Your Name |
//| |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Your Name"
#property link ""
#property version "1.00"
#property strict

//--- Input Parameters
input double RiskPercentage = 1.0; // Risk percentage of account balance
input int MA_Period_Fast = 5; // Fast Moving Average period
input int MA_Period_Slow = 20; // Slow Moving Average period
input int Stochastic_K = 3; // Stochastic %K period
input int Stochastic_D = 3; // Stochastic %D period
input int Stochastic_Slowing = 3; // Stochastic Slowing period

//--- Global Variables
double Lots;
double StopLoss;
double TakeProfit1;
double TakeProfit2;
double TakeProfit3;

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// تنها در زمان‌های مجاز (لندن و نیویورک) و در آغاز کندل جدید اجرا شود
if (!IsTradingTimeAllowed() || !IsNewBar())
return;

// محاسبه میانگین‌های متحرک با داده کندل قبلی (shift = 1)
double ma_fast = CalculateMA(_Symbol, _Period, MA_Period_Fast, PRICE_CLOSE, 1);
double ma_slow = CalculateMA(_Symbol, _Period, MA_Period_Slow, PRICE_CLOSE, 1);

// محاسبه شاخص استوکستیک با پارامترهای K=3، D=3، slowing=3
double stoch_k_prev, stoch_d_prev;
double stoch_k_curr, stoch_d_curr;
CalculateStochastic(_Symbol, _Period, Stochastic_K, Stochastic_D, Stochastic_Slowing, stoch_k_prev, stoch_d_prev, 2);
CalculateStochastic(_Symbol, _Period, Stochastic_K, Stochastic_D, Stochastic_Slowing, stoch_k_curr, stoch_d_curr, 1);

// شرط ورود به معامله خرید: MA_fast > MA_slow، عبور %K از %D به سمت بالا
if (ma_fast > ma_slow &&
stoch_k_prev < stoch_d_prev &&
stoch_k_curr > stoch_d_curr &&
IsConditionMetForBuy(20)) // بررسی 7 کندل اخیر
{
CloseExistingOrders(ORDER_TYPE_SELL); // بسته شدن سفارش‌های فروش موجود
if (!IsOrderOpen(ORDER_TYPE_BUY))
OpenBuyOrder();
}

// شرط ورود به معامله فروش: MA_fast < MA_slow، عبور %K از %D به سمت پایین
if (ma_fast < ma_slow &&
stoch_k_prev > stoch_d_prev &&
stoch_k_curr < stoch_d_curr &&
IsConditionMetForSell(20)) // بررسی 7 کندل اخیر
{
CloseExistingOrders(ORDER_TYPE_BUY); // بسته شدن سفارش‌های خرید موجود
if (!IsOrderOpen(ORDER_TYPE_SELL))
OpenSellOrder();
}

// مدیریت توقف ضرر: انتقال SL به قیمت ورود (Break-even) تنها برای سفارش‌های با کامنت "TP2"
CheckAndMoveStopLoss();

// گزارش عملکرد
ReportPerformance();
}

//+------------------------------------------------------------------+
//| Function to calculate Moving Average manually |
//+------------------------------------------------------------------+
double CalculateMA(const string symbol, ENUM_TIMEFRAMES timeframe, int period, int applied_price, int shift = 0)
{
double sum = 0;
for (int i = 0; i < period; i++)
{
double price = 0;
int index = i + shift;
switch (applied_price)
{
case PRICE_OPEN: price = iOpen(symbol, timeframe, index); break;
case PRICE_HIGH: price = iHigh(symbol, timeframe, index); break;
case PRICE_LOW: price = iLow(symbol, timeframe, index); break;
case PRICE_CLOSE: price = iClose(symbol, timeframe, index); break;
default: price = iClose(symbol, timeframe, index); break;
}
sum += price;
}
return (sum / period);
}

//+------------------------------------------------------------------+
//| Function to calculate Stochastic Oscillator manually |
//+------------------------------------------------------------------+
void CalculateStochastic(const string symbol, ENUM_TIMEFRAMES timeframe, int KPeriod, int DPeriod, int slowing, double &stoch_k, double &stoch_d, int shift)
{
double highest_high = -DBL_MAX;
double lowest_low = DBL_MAX;
for (int i = 0; i < KPeriod; i++)
{
double high = iHigh(symbol, timeframe, i + shift);
double low = iLow(symbol, timeframe, i + shift);
if (high > highest_high)
highest_high = high;
if (low < lowest_low)
lowest_low = low;
}
double current_close = iClose(symbol, timeframe, shift);
if (highest_high == lowest_low)
stoch_k = 50;
else
stoch_k = ((current_close - lowest_low) / (highest_high - lowest_low)) * 100;

// محاسبه %D به عنوان میانگین ساده %K در DPeriod کندل
double sum_k = 0;
for (int i = 0; i < DPeriod; i++)
{
double hh = -DBL_MAX, ll = DBL_MAX;
for (int j = 0; j < KPeriod; j++)
{
double high = iHigh(symbol, timeframe, j + shift + i);
double low = iLow(symbol, timeframe, j + shift + i);
if (high > hh)
hh = high;
if (low < ll)
ll = low;
}
double close_val = iClose(symbol, timeframe, shift + i);
double k_val = (hh == ll) ? 50 : ((close_val - ll) / (hh - ll)) * 100;
sum_k += k_val;
}
stoch_d = sum_k / DPeriod;
}

//+------------------------------------------------------------------+
//| Function to check if trading time is allowed |
//+------------------------------------------------------------------+
bool IsTradingTimeAllowed()
{
datetime currentTime = TimeCurrent();
int hour = GetHour(currentTime);
if (hour >= 8 && hour < 17)
return (true);
if (hour >= 13 && hour < 19)
return (true);
return (false);
}

//+------------------------------------------------------------------+
//| Function to extract hour from timestamp |
//+------------------------------------------------------------------+
int GetHour(datetime time)
{
return ((int)(time / 3600) % 24);
}

//+------------------------------------------------------------------+
//| Function to check if an order of a specific type is open |
//+------------------------------------------------------------------+
bool IsOrderOpen(int type)
{
for (int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket))
{
if (PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_TYPE) == type)
return (true);
}
}
return (false);
}

//+------------------------------------------------------------------+
//| Function to close all orders of a specific type |
//+------------------------------------------------------------------+
void CloseExistingOrders(int type)
{
for (int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket))
{
if (PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_TYPE) == type)
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.position = ticket;
if (type == ORDER_TYPE_BUY)
{
request.type = ORDER_TYPE_SELL;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
}
else if (type == ORDER_TYPE_SELL)
{
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
}
request.deviation = 5;
request.comment = "Close Order";
if (!OrderSend(request, result))
Print("Error closing order: ", GetLastError());
}
}
}
}

//+------------------------------------------------------------------+
//| Function to calculate lot size based on risk management |
//+------------------------------------------------------------------+
double CalculateLotSizeForTrade(double entry, double stop_loss)
{
double risk_amount = AccountInfoDouble(ACCOUNT_BALANCE) * 0.01; // 1% ریسک
double pip_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double sl_pips = MathAbs(entry - stop_loss) / _Point;
double lot_size = risk_amount / (sl_pips * pip_value);
lot_size = NormalizeDouble(lot_size, 2);
double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
if (lot_size < min_lot)
lot_size = min_lot;
return (lot_size);
}

//+------------------------------------------------------------------+
//| Function to open a BUY order |
//+------------------------------------------------------------------+
void OpenBuyOrder()
{
double entry = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double ma20 = CalculateMA(_Symbol, _Period, 20, PRICE_CLOSE, 1); // MA20 از کندل قبلی
double stop_loss = ma20;

// محاسبه TP1, TP2, TP3 بر اساس فاصله استراحت لاس
double sl_distance = MathAbs(entry - stop_loss);
double tp1 = entry + sl_distance;
double tp2 = entry + 2 * sl_distance;
double tp3 = entry + 3 * sl_distance;

double lot_size = CalculateLotSizeForTrade(entry, stop_loss);

// بخش 1 (50% حجم) با TP1
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lot_size * 0.5;
request.type = ORDER_TYPE_BUY;
request.price = entry;
request.sl = stop_loss;
request.tp = tp1;
request.deviation = 5;
request.comment = "BUY Order - TP1";
if (!OrderSend(request, result))
Print("Error opening BUY order (TP1): ", GetLastError());
else
Print("BUY order (TP1) opened: SL=", stop_loss, " TP=", tp1);
}

// بخش 2 (30% حجم) با TP2
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lot_size * 0.3;
request.type = ORDER_TYPE_BUY;
request.price = entry;
request.sl = stop_loss;
request.tp = tp2;
request.deviation = 5;
request.comment = "BUY Order - TP2";
if (!OrderSend(request, result))
Print("Error opening BUY order (TP2): ", GetLastError());
else
Print("BUY order (TP2) opened: TP=", tp2);
}

// بخش 3 (20% حجم) با TP3
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lot_size * 0.2;
request.type = ORDER_TYPE_BUY;
request.price = entry;
request.sl = stop_loss;
request.tp = tp3;
request.deviation = 5;
request.comment = "BUY Order - TP3";
if (!OrderSend(request, result))
Print("Error opening BUY order (TP3): ", GetLastError());
else
Print("BUY order (TP3) opened: TP=", tp3);
}
}

//+------------------------------------------------------------------+
//| Function to open a SELL order |
//+------------------------------------------------------------------+
void OpenSellOrder()
{
double entry = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ma20 = CalculateMA(_Symbol, _Period, 20, PRICE_CLOSE, 1); // MA20 از کندل قبلی
double stop_loss = ma20;

// محاسبه TP1, TP2, TP3 بر اساس فاصله استراحت لاس
double sl_distance = MathAbs(entry - stop_loss);
double tp1 = entry - sl_distance;
double tp2 = entry - 2 * sl_distance;
double tp3 = entry - 3 * sl_distance;

double lot_size = CalculateLotSizeForTrade(entry, stop_loss);

// بخش 1 (50% حجم) با TP1
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lot_size * 0.5;
request.type = ORDER_TYPE_SELL;
request.price = entry;
request.sl = stop_loss;
request.tp = tp1;
request.deviation = 5;
request.comment = "SELL Order - TP1";
if (!OrderSend(request, result))
Print("Error opening SELL order (TP1): ", GetLastError());
else
Print("SELL order (TP1) opened: SL=", stop_loss, " TP=", tp1);
}

// بخش 2 (30% حجم) با TP2
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lot_size * 0.3;
request.type = ORDER_TYPE_SELL;
request.price = entry;
request.sl = stop_loss;
request.tp = tp2;
request.deviation = 5;
request.comment = "SELL Order - TP2";
if (!OrderSend(request, result))
Print("Error opening SELL order (TP2): ", GetLastError());
else
Print("SELL order (TP2) opened: TP=", tp2);
}

// بخش 3 (20% حجم) با TP3
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lot_size * 0.2;
request.type = ORDER_TYPE_SELL;
request.price = entry;
request.sl = stop_loss;
request.tp = tp3;
request.deviation = 5;
request.comment = "SELL Order - TP3";
if (!OrderSend(request, result))
Print("Error opening SELL order (TP3): ", GetLastError());
else
Print("SELL order (TP3) opened: TP=", tp3);
}
}

//+------------------------------------------------------------------+
//| Function to check if conditions are met for BUY |
//+------------------------------------------------------------------+
bool IsConditionMetForBuy(int period_ma)
{
double ma_value = CalculateMA(_Symbol, _Period, period_ma, PRICE_CLOSE, 1);
int count_above_ma = 0;
for (int i = 1; i <= 7; i++)
{
if (iClose(_Symbol, _Period, i) > ma_value)
count_above_ma++;
}
return (count_above_ma == 7);
}

//+------------------------------------------------------------------+
//| Function to check if conditions are met for SELL |
//+------------------------------------------------------------------+
bool IsConditionMetForSell(int period_ma)
{
double ma_value = CalculateMA(_Symbol, _Period, period_ma, PRICE_CLOSE, 1);
int count_below_ma = 0;
for (int i = 1; i <= 7; i++)
{
if (iClose(_Symbol, _Period, i) < ma_value)
count_below_ma++;
}
return (count_below_ma == 7);
}

//+------------------------------------------------------------------+
//| Function to check if it's a new bar |
//+------------------------------------------------------------------+
bool IsNewBar()
{
static datetime last_bar_time = 0;
datetime current_bar_time = iTime(_Symbol, _Period, 0);
if (current_bar_time > last_bar_time)
{
last_bar_time = current_bar_time;
return (true);
}
return (false);
}

//+------------------------------------------------------------------+
//| Function to move stop loss to break-even |
//+------------------------------------------------------------------+
void MoveStopLossToBreakEven(ulong ticket, double break_even_price)
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.sl = break_even_price;
if (!OrderSend(request, result))
Print("Error moving Stop Loss to Break-Even: ", GetLastError());
else
Print("Stop Loss moved to Break-Even: ", break_even_price);
}

//+------------------------------------------------------------------+
//| Function to check and move stop loss |
//+------------------------------------------------------------------+
void CheckAndMoveStopLoss()
{
for (int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket))
{
int type = PositionGetInteger(POSITION_TYPE);
double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
double current_price = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_BID)
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
string comment = PositionGetString(POSITION_COMMENT);

if (StringFind(comment, "TP2") != -1)
{
if (type == ORDER_TYPE_BUY)
{
if (current_price >= PositionGetDouble(POSITION_TP))
MoveStopLossToBreakEven(ticket, open_price);
}
else if (type == ORDER_TYPE_SELL)
{
if (current_price <= PositionGetDouble(POSITION_TP))
MoveStopLossToBreakEven(ticket, open_price);
}
}
}
}
}

//+------------------------------------------------------------------+
//| Function to report performance |
//+------------------------------------------------------------------+
void ReportPerformance()
{
double total_profit = 0;
int total_trades = 0;
for (int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket))
{
total_profit += PositionGetDouble(POSITION_PROFIT);
total_trades++;
}
}
Print("Total Trades: ", total_trades, ", Total Profit: ", total_profit);
}

Aviso legal