//+------------------------------------------------------------------+
//| Проверка корректности стоп-уровней |
//+------------------------------------------------------------------+
bool ValidateStopLevels(double price, double &sl, double &tp, int orderType)
{
double point = MarketInfo(Symbol(), MODE_POINT);
double spread = MarketInfo(Symbol(), MODE_SPREAD) * point;
double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * point;
double minDistance = stopLevel + spread;
// Если стоп-лосс не установлен, пропускаем проверку
if(sl == 0 && tp == 0) return true;
if(orderType == OP_BUY)
{
if(sl > 0 && (price - sl) < minDistance)
{
Print("Корректируем SL для BUY. Было: ", sl, " Стало: ", price - minDistance);
sl = price - minDistance;
}
if(tp > 0 && (tp - price) < minDistance)
{
Print("Корректируем TP для BUY. Было: ", tp, " Стало: ", price + minDistance);
tp = price + minDistance;
}
}
else if(orderType == OP_SELL)
{
if(sl > 0 && (sl - price) < minDistance)
{
Print("Корректируем SL для SELL. Было: ", sl, " Стало: ", price + minDistance);
sl = price + minDistance;
}
if(tp > 0 && (price - tp) < minDistance)
{
Print("Корректируем TP для SELL. Было: ", tp, " Стало: ", price - minDistance);
tp = price - minDistance;
}
}
// Нормализуем цены
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
return true;
}
//+------------------------------------------------------------------+
//| Определение направления ордера |
//+------------------------------------------------------------------+
int GetOrderDirection()
{
// Получаем информацию о последней закрытой свече
double open = iOpen(Symbol(), PERIOD_CURRENT, 1);
double close = iClose(Symbol(), PERIOD_CURRENT, 1);
bool isBullish = (close > open);
if(DirectionMode == 1)
{
// Ордер в направлении последней свечи
return isBullish ? OP_BUY : OP_SELL;
}
else if(DirectionMode == 2)
{
// Ордер против направления последней свечи
return isBullish ? OP_SELL : OP_BUY;
}
return -1;
}
//+------------------------------------------------------------------+
//| Обновление размера лота на основе изменения баланса |
//+------------------------------------------------------------------+
void UpdateLotSize()
{
double currentBalance = AccountBalance();
double balanceChange = currentBalance / balanceReference;
// Изменяем лот пропорционально изменению баланса
currentLot = NormalizeDouble(InitialLot * balanceChange, 2);
// Проверяем минимальный и максимальный лот
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
if(currentLot < minLot) currentLot = minLot;
if(currentLot > maxLot) currentLot = maxLot;
// Проверяем шаг лота
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
currentLot = MathRound(currentLot / lotStep) * lotStep;
currentLot = NormalizeDouble(currentLot, 2);
Print("Баланс: ", currentBalance, ", Референс: ", balanceReference,
", Новый лот: ", currentLot);
}
//+------------------------------------------------------------------+
//| Расчет стоп-лосса |
//+------------------------------------------------------------------+
double CalculateSL(double price, int orderType)
{
if(StopLoss == 0) return 0;
double point = MarketInfo(Symbol(), MODE_POINT);
double slPoints = StopLoss * point;
if(orderType == OP_BUY)
return NormalizeDouble(price - slPoints, Digits);
else if(orderType == OP_SELL)
return NormalizeDouble(price + slPoints, Digits);
return 0;
}
//+------------------------------------------------------------------+
//| Расчет тейк-профита |
//+------------------------------------------------------------------+
double CalculateTP(double price, int orderType)
{
if(TakeProfit == 0) return 0;
double point = MarketInfo(Symbol(), MODE_POINT);
double tpPoints = TakeProfit * point;
if(orderType == OP_BUY)
return NormalizeDouble(price + tpPoints, Digits);
else if(orderType == OP_SELL)
return NormalizeDouble(price - tpPoints, Digits);
return 0;
}
//+------------------------------------------------------------------+
//| Закрытие всех ордеров |
//+------------------------------------------------------------------+
void CloseAllOrders()
{
int closedCount = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == 0)
{
double closePrice = 0;
if(OrderType() == OP_BUY)
closePrice = Bid;
else if(OrderType() == OP_SELL)
closePrice = Ask;
if(OrderClose(OrderTicket(), OrderLots(), closePrice, 3, clrRed))
{
closedCount++;
Print("Ордер закрыт в 00:00: ", OrderTypeToString(OrderType()),
", Прибыль: ", OrderProfit());
}
else
{
Print("Ошибка закрытия ордера ", OrderTypeToString(OrderType()), ": ", GetLastError());
}
}
}
}
if(closedCount > 0)
{
// Обновляем референсный баланс при закрытии дня
balanceReference = AccountBalance();
Print("Закрыто ордеров: ", closedCount, ". Новый референсный баланс: ", balanceReference);
}
}
//+------------------------------------------------------------------+
//| Подсчет открытых ордеров |
//+------------------------------------------------------------------+
int CountOpenOrders()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == 0)
{
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| Получение даты без времени |
//+------------------------------------------------------------------+
datetime TimeCurrentDate()
{
MqlDateTime timeStruct;
TimeToStruct(TimeCurrent(), timeStruct);
timeStruct.hour = 0;
timeStruct.min = 0;
timeStruct.sec = 0;
return StructToTime(timeStruct);
}
//+------------------------------------------------------------------+
//| Конвертация типа ордера в строку |
//+------------------------------------------------------------------+
string OrderTypeToString(int orderType)
{
if(orderType == OP_BUY) return "BUY";
if(orderType == OP_SELL) return "SELL";
return "UNKNOWN";
}
//+------------------------------------------------------------------+
//| Получение описания ошибки |
//+------------------------------------------------------------------+
string GetErrorDescription(int errorCode)
{
switch(errorCode)
{
case 130: return "Неправильные стопы. Проверьте минимальные расстояния для стоп-ордеров.";
case 131: return "Неправильный объем.";
case 132: return "Неправильная цена.";
case 133: return "Торговля запрещена.";
case 134: return "Недостаточно денег.";
case 135: return "Цена изменилась.";
case 136: return "Нет цен.";
case 137: return "Брокер занят.";
case 138: return "Требуется перезагрузка цен.";
case 139: return "Ордер заблокирован и уже обрабатывается.";
case 140: return "Разрешение на торговлю запрещено.";
case 146: return "Торговая подсистема занята.";
default: return "Неизвестная ошибка.";
}
}


igrun