← К каталогу
Исходный код · ID 4040

BlueMoon EA

bluemoon_ea_v3_4_netting_volume_fix.mq5
Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

BlueMoon EA — торговый советник для платформы MetaTrader 5, работающий на сеттинг-счётах (неттинг). Советник анализирует ценовые данные с помощью скользящей средней и полос отклонения, формирует торговые сигналы на вход и управляет существующими позициями. Поддерживает сетку позиций в одном направлении, управление прибылью корзины и защиту от просадки.

Советник отслеживает рыночные события и открытые позиции, управляет ордерами через встроенный торговый класс CTrade. Реализует фильтрацию по спреду, проверку маржи и защиту от повторных заявок в одну и ту же секунду. При достижении заданного уровня просадки торговля блокируется.

В интерфейсе предусмотрена информационная панель с отображением текущего состояния, статуса сигналов, состава корзин, риск-метра и последней закрытой сделки. Панель настраивается по позиции и размеру шрифта.

Настройки программы

НастройкаОписание
InpEAName Название советника — Текстовое имя советника, отображаемое в интерфейсе и на панели.
InpMagicNumber Магический номер — Уникальный идентификатор ордеров и позиций советника.
InpSignalTimeframe Таймфрейм сигнала — Таймфрейм, на котором строится индикатор и генерируются торговые сигналы.
InpMAPeriod Период MA — Период скользящей средней, используемой для расчёта базовой линии.
InpMAMethod Метод MA — Тип скользящей средней (например, EMA, SMA) для расчёта базовой линии.
InpEnvelopeDeviationPercent Отклонение энvelope в процентах — Процентное отклонение полос от базовой линии скользящей средней.
InpInitialLot Начальный лот — Размер лота для первого входящего ордера.
InpLotIncrement Приращение лота — Увеличение размера лота на каждом следующем уровне сетки.
InpMaxLot Максимальный лот — Максимально допустимый размер лота для одной позиции.
InpGridDistancePips Расстояние сетки в пипсах — Расстояние в пипсах между уровнями сетки для наращивания позиции.
InpSingleTradeTPPips Тейк-профит для одной сделки в пипсах — Фиксированный тейк-профит в пипсах для закрытия позиции, содержащей один уровень сетки.
InpBasketProfitTargetMoney Цель прибыли корзины — Целевая сумма чистой прибыли корзины позиций в одном направлении для её закрытия.
InpMaxPositionsPerDirection Максимум позиций в направлении — Максимальное количество уровней сетки в одном торговом направлении.
InpTradeOnlyOnNewBar Торговать только на новом баре — Разрешает открытие новых позиций только при появлении нового бара на сигнальном таймфрейме.
InpUseClosedBarSignal Использовать сигнал закрытого бара — Использовать данные закрытой свечи для формирования сигнала на вход вместо текущих цен.
InpAllowBuy Разрешить покупку — Разрешает открытие длинных позиций при наличии сигнала на покупку.
InpAllowSell Разрешить продажу — Разрешает открытие коротких позиций при наличии сигнала на продажу.
InpAllowRecentSignalOnStartup Разрешить недавний сигнал при запуске — При запуске советника пытается восстановить сигнал с недавно закрытой свечи.
InpMaxSignalAgeBars Максимальный возраст сигнала в барах — Максимальное количество баров назад, в пределах которых ищется подходящий сигнал при запуске.
InpRecentSignalMaxDistancePips Максимальное расстояние недавнего сигнала в пипсах — Допустимое расстояние в пипсах между ценой и уровнем сигнала для его восстановления при запуске.
InpMaxSpreadPips Максимальный спред в пипсах — Максимально допустимый спред в пипсах для открытия новых позиций.
InpSlippagePoints Проскальзывание в пунктах — Допустимое проскальзывание в пунктах при исполнении ордеров.
InpEnableTotalDrawdownProtection Включить защиту от просадки — Активирует блокировку торговли при достижении заданного уровня просадки.
InpMaxTotalDrawdownPercent Максимальная просадка в процентах — Порог просадки, при достижении которого срабатывает защита и блокировка торговли.
InpUsePeakEquityForDrawdown Использовать пиковое эквити для просадки — При включении расчёт просадки ведётся от пикового значения эквити, а не от баланса.
InpLockTradingAfterDD Блокировка торговли после просадки — После срабатывания защиты от просадки торговля блокируется до перезапуска советника.
InpShowDashboard Показывать панель — Включает отображение информационной панели на графике.
InpDashboardX Позиция панели X — Горизонтальная координата левого верхнего угла панели в пикселях.
InpDashboardY Позиция панели Y — Вертикальная координата левого верхнего угла панели в пикселях.
InpDashboardWidth Ширина панели — Ширина информационной панели в пикселях.
InpDashboardFontSize Размер шрифта панели — Размер шрифта текста на информационной панели.
Получить полный код

Поиск по коду файла

#property strict
#property version   "3.40"
#property description "BlueMoon EA - "

#include <Trade/Trade.mqh>
CTrade trade;

input string InpEAName = "BlueMoon EA";
input ulong  InpMagicNumber = 31072026;

input ENUM_TIMEFRAMES InpSignalTimeframe = PERIOD_M5;
input int    InpMAPeriod = 14;
input ENUM_MA_METHOD InpMAMethod = MODE_EMA;
input double InpEnvelopeDeviationPercent = 0.10;
input double InpInitialLot = 0.01;
input double InpLotIncrement = 0.01;
input double InpMaxLot = 0.10;
input int    InpGridDistancePips = 17;
input int    InpSingleTradeTPPips = 10;
input double InpBasketProfitTargetMoney = 1.00;
input int    InpMaxPositionsPerDirection = 10;
input bool   InpTradeOnlyOnNewBar = true;
input bool   InpUseClosedBarSignal = true;
input bool   InpAllowBuy = true;
input bool   InpAllowSell = true;

input bool   InpAllowRecentSignalOnStartup = true;
input int    InpMaxSignalAgeBars = 2;
input double InpRecentSignalMaxDistancePips = 3.0;

input double InpMaxSpreadPips = 2.50;
input int    InpSlippagePoints = 20;

input bool   InpEnableTotalDrawdownProtection = true;
input double InpMaxTotalDrawdownPercent = 51.0;
input bool   InpUsePeakEquityForDrawdown = true;
input bool   InpCloseAllAccountPositionsOnDD = false;
input bool   InpLockTradingAfterDD = true;

input bool   InpShowDashboard = true;
input int    InpDashboardX = 12;
input int    InpDashboardY = 22;
input int    InpDashboardWidth = 420;
input int    InpDashboardFontSize = 9;

int maHandle = INVALID_HANDLE;
datetime lastSignalBar = 0;
double peakEquity = 0.0;
bool drawdownLock = false;
string currentStatus = "INITIALISING";
string blockingReason = "";
string lastAction = "None";
string lastCloseReason = "No BlueMoon trade closed yet";
datetime lastTickTime = 0;
bool startupSignalChecked = false;

string PREFIX = "BM34_";

bool isNettingAccount = false;
datetime lastBuyAttemptTime = 0;
datetime lastSellAttemptTime = 0;
double lastBuyAttemptPrice = 0.0;
double lastSellAttemptPrice = 0.0;

double PipSize()
{
   int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   return (digits == 3 || digits == 5) ? point * 10.0 : point;
}

double CurrentSpreadPips()
{
   MqlTick tick;
   if(!SymbolInfoTick(_Symbol, tick)) return 0.0;
   return (tick.ask - tick.bid) / PipSize();
}

double NormalizeVolume(double volume)
{
   double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double step   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   volume = MathMax(minLot, MathMin(maxLot, volume));
   if(step > 0.0)
      volume = MathFloor(volume / step + 1e-8) * step;

   int volDigits = 2;
   if(step == 0.1) volDigits = 1;
   else if(step == 0.001) volDigits = 3;

   return NormalizeDouble(volume, volDigits);
}

bool IsOurPositionByIndex(int index)
{
   ulong ticket = PositionGetTicket(index);
   if(ticket == 0) return false;
   if(!PositionSelectByTicket(ticket)) return false;
   return ((ulong)PositionGetInteger(POSITION_MAGIC) == InpMagicNumber &&
           PositionGetString(POSITION_SYMBOL) == _Symbol);
}

int CountPositions(ENUM_POSITION_TYPE type)
{
   int count = 0;
   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      if(!IsOurPositionByIndex(i)) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == type)
         count++;
   }
   return count;
}

double TotalLots(ENUM_POSITION_TYPE type)
{
   double lots = 0.0;
   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      if(!IsOurPositionByIndex(i)) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == type)
         lots += PositionGetDouble(POSITION_VOLUME);
   }
   return lots;
}

int CountGridLevels(ENUM_POSITION_TYPE type)
{
   if(!isNettingAccount)
      return CountPositions(type);

   double total = TotalLots(type);
   if(total <= 0.0) return 0;

   double accumulated = 0.0;
   for(int level = 0; level < InpMaxPositionsPerDirection; ++level)
   {
      double levelLot = NormalizeVolume(MathMin(InpMaxLot,
                                  InpInitialLot + level * InpLotIncrement));
      accumulated += levelLot;
      double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
      double tolerance = MathMax(step * 0.51, 1e-8);
      if(total <= accumulated + tolerance)
         return level + 1;
   }
   return InpMaxPositionsPerDirection;
}

double CurrentSymbolDirectionalVolume(ENUM_ORDER_TYPE orderType)
{
   double volume = 0.0;
   ENUM_POSITION_TYPE wanted = (orderType == ORDER_TYPE_BUY ?
                                POSITION_TYPE_BUY : POSITION_TYPE_SELL);

   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0 || !PositionSelectByTicket(ticket)) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == wanted)
         volume += PositionGetDouble(POSITION_VOLUME);
   }

   for(int i = OrdersTotal() - 1; i >= 0; --i)
   {
      ulong ticket = OrderGetTicket(i);
      if(ticket == 0 || !OrderSelect(ticket)) continue;
      if(OrderGetString(ORDER_SYMBOL) != _Symbol) continue;
      ENUM_ORDER_TYPE t = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE);
      bool sameDirection = (orderType == ORDER_TYPE_BUY &&
                            (t == ORDER_TYPE_BUY_LIMIT || t == ORDER_TYPE_BUY_STOP ||
                             t == ORDER_TYPE_BUY_STOP_LIMIT)) ||
                           (orderType == ORDER_TYPE_SELL &&
                            (t == ORDER_TYPE_SELL_LIMIT || t == ORDER_TYPE_SELL_STOP ||
                             t == ORDER_TYPE_SELL_STOP_LIMIT));
      if(sameDirection)
         volume += OrderGetDouble(ORDER_VOLUME_CURRENT);
   }
   return volume;
}

double LastEntryDealPrice(ENUM_POSITION_TYPE type)
{
   if(!HistorySelect(0, TimeCurrent())) return 0.0;
   ENUM_DEAL_TYPE wanted = (type == POSITION_TYPE_BUY ? DEAL_TYPE_BUY : DEAL_TYPE_SELL);

   for(int i = HistoryDealsTotal() - 1; i >= 0; --i)
   {
      ulong deal = HistoryDealGetTicket(i);
      if(deal == 0) continue;
      if((ulong)HistoryDealGetInteger(deal, DEAL_MAGIC) != InpMagicNumber) continue;
      if(HistoryDealGetString(deal, DEAL_SYMBOL) != _Symbol) continue;
      if((ENUM_DEAL_TYPE)HistoryDealGetInteger(deal, DEAL_TYPE) != wanted) continue;
      ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal, DEAL_ENTRY);
      if(entry == DEAL_ENTRY_IN || entry == DEAL_ENTRY_INOUT)
         return HistoryDealGetDouble(deal, DEAL_PRICE);
   }
   return 0.0;
}

double BasketNet(ENUM_POSITION_TYPE type)
{
   double net = 0.0;
   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      if(!IsOurPositionByIndex(i)) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) != type) continue;
      net += PositionGetDouble(POSITION_PROFIT);
      net += PositionGetDouble(POSITION_SWAP);
   }
   return net;
}

double BasketSwap(ENUM_POSITION_TYPE type)
{
   double value = 0.0;
   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      if(!IsOurPositionByIndex(i)) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == type)
         value += PositionGetDouble(POSITION_SWAP);
   }
   return value;
}

double WeightedAverageEntry(ENUM_POSITION_TYPE type)
{
   double weighted = 0.0, lots = 0.0;
   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      if(!IsOurPositionByIndex(i)) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) != type) continue;
      double v = PositionGetDouble(POSITION_VOLUME);
      weighted += PositionGetDouble(POSITION_PRICE_OPEN) * v;
      lots += v;
   }
   return (lots > 0.0 ? weighted / lots : 0.0);
}

double NewestEntry(ENUM_POSITION_TYPE type)
{
   datetime newestTime = 0;
   double newestPrice = 0.0;
   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      if(!IsOurPositionByIndex(i)) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) != type) continue;
      datetime t = (datetime)PositionGetInteger(POSITION_TIME);
      if(t >= newestTime)
      {
         newestTime = t;
         newestPrice = PositionGetDouble(POSITION_PRICE_OPEN);
      }
   }
   return newestPrice;
}

double OldestEntry(ENUM_POSITION_TYPE type)
{
   datetime oldestTime = D'2099.12.31';
   double oldestPrice = 0.0;
   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      if(!IsOurPositionByIndex(i)) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) != type) continue;
      datetime t = (datetime)PositionGetInteger(POSITION_TIME);
      if(t <= oldestTime)
      {
         oldestTime = t;
         oldestPrice = PositionGetDouble(POSITION_PRICE_OPEN);
      }
   }
   return oldestPrice;
}

double NextLot(ENUM_POSITION_TYPE type)
{
   int count = CountGridLevels(type);
   return NormalizeVolume(MathMin(InpMaxLot, InpInitialLot + count * InpLotIncrement));
}

bool IsNewSignalBar()
{
   datetime bar = iTime(_Symbol, InpSignalTimeframe, 0);
   if(bar == 0) return false;
   if(bar != lastSignalBar)
   {
      lastSignalBar = bar;
      return true;
   }
   return false;
}

bool GetEnvelope(double &center, double &upper, double &lower)
{
   double ma[1];
   if(CopyBuffer(maHandle, 0, 0, 1, ma) != 1) return false;
   center = ma[0];
   double deviation = InpEnvelopeDeviationPercent / 100.0;
   upper = center * (1.0 + deviation);
   lower = center * (1.0 - deviation);
   return true;
}

bool GetEnvelopeAtShift(int shift, double &center, double &upper, double &lower)
{
   if(shift < 0) return false;

   double ma[1];
   if(CopyBuffer(maHandle, 0, shift, 1, ma) != 1) return false;

   center = ma[0];
   double deviation = InpEnvelopeDeviationPercent / 100.0;
   upper = center * (1.0 + deviation);
   lower = center * (1.0 - deviation);
   return true;
}

double CurrentDrawdownPercent()
{
   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double base = AccountInfoDouble(ACCOUNT_BALANCE);

   if(InpUsePeakEquityForDrawdown)
   {
      if(equity > peakEquity) peakEquity = equity;
      base = MathMax(base, peakEquity);
   }

   if(base <= 0.0) return 0.0;
   return MathMax(0.0, (base - equity) / base * 100.0);
}

void DeletePendingOrders(bool allAccountOrders)
{
   for(int i = OrdersTotal() - 1; i >= 0; --i)
   {
      ulong ticket = OrderGetTicket(i);
      if(ticket == 0 || !OrderSelect(ticket)) continue;
      if(!allAccountOrders)
      {
         if((ulong)OrderGetInteger(ORDER_MAGIC) != InpMagicNumber) continue;
         if(OrderGetString(ORDER_SYMBOL) != _Symbol) continue;
      }
      trade.OrderDelete(ticket);
   }
}

void ClosePositions(bool allAccountPositions, string reason)
{
   lastCloseReason = reason;
   lastAction = reason;

   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0 || !PositionSelectByTicket(ticket)) continue;

      if(!allAccountPositions)
      {
         if((ulong)PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue;
         if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      }

      trade.PositionClose(ticket, InpSlippagePoints);
   }
   DeletePendingOrders(allAccountPositions);
}

void ClosePositionsByType(ENUM_POSITION_TYPE type, string reason)
{
   lastCloseReason = reason;
   lastAction = reason;

   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0 || !PositionSelectByTicket(ticket)) continue;
      if((ulong)PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) != type) continue;

      if(!trade.PositionClose(ticket, InpSlippagePoints))
         Print("BlueMoon close failed for ticket ", ticket, ": ",
               trade.ResultRetcode(), " ", trade.ResultRetcodeDescription());
   }
}

bool CheckDrawdownProtection()
{
   double dd = CurrentDrawdownPercent();
   if(!InpEnableTotalDrawdownProtection) return false;
   if(dd < InpMaxTotalDrawdownPercent) return false;

   currentStatus = "DRAWDOWN PROTECTION TRIGGERED";
   blockingReason = StringFormat("Total drawdown %.2f%% reached %.2f%% limit",
                                 dd, InpMaxTotalDrawdownPercent);

   ClosePositions(InpCloseAllAccountPositionsOnDD,
                  StringFormat("TOTAL DRAWDOWN STOP %.2f%%", dd));

   if(InpLockTradingAfterDD)
      drawdownLock = true;

   return true;
}

bool CanOpenPosition(ENUM_ORDER_TYPE orderType, double volume, string &reason)
{
   reason = "";

   if(!TerminalInfoInteger(TERMINAL_CONNECTED))
   {
      reason = "Terminal is not connected";
      return false;
   }
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) ||
      !MQLInfoInteger(MQL_TRADE_ALLOWED) ||
      !AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
   {
      reason = "Automated trading is not allowed";
      return false;
   }

   long tradeMode = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE);
   if(tradeMode == SYMBOL_TRADE_MODE_DISABLED || tradeMode == SYMBOL_TRADE_MODE_CLOSEONLY)
   {
      reason = "Symbol is not open for new trades";
      return false;
   }
   if(orderType == ORDER_TYPE_BUY && tradeMode == SYMBOL_TRADE_MODE_SHORTONLY)
   {
      reason = "Symbol allows sell orders only";
      return false;
   }
   if(orderType == ORDER_TYPE_SELL && tradeMode == SYMBOL_TRADE_MODE_LONGONLY)
   {
      reason = "Symbol allows buy orders only";
      return false;
   }

   MqlTick tick;
   if(!SymbolInfoTick(_Symbol, tick) || tick.ask <= 0.0 || tick.bid <= 0.0)
   {
      reason = "Valid market prices are unavailable";
      return false;
   }

   volume = NormalizeVolume(volume);

   double symbolVolumeLimit = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT);
   if(symbolVolumeLimit > 0.0)
   {
      double used = CurrentSymbolDirectionalVolume(orderType);
      double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
      double tolerance = MathMax(step * 0.1, 1e-8);
      if(used + volume > symbolVolumeLimit + tolerance)
      {
         reason = StringFormat("Broker volume limit reached: used %.2f + requested %.2f > %.2f",
                               used, volume, symbolVolumeLimit);
         return false;
      }
   }

   double price = (orderType == ORDER_TYPE_BUY ? tick.ask : tick.bid);
   double margin = 0.0;
   if(!OrderCalcMargin(orderType, _Symbol, volume, price, margin))
   {
      reason = StringFormat("Margin calculation failed: %d", GetLastError());
      return false;
   }
   if(AccountInfoDouble(ACCOUNT_MARGIN_FREE) < margin)
   {
      reason = StringFormat("Insufficient free margin: need %.2f", margin);
      return false;
   }
   return true;
}

bool OpenPosition(ENUM_ORDER_TYPE orderType, double volume, string comment)
{
   volume = NormalizeVolume(volume);

   MqlTick attemptTick;
   if(!SymbolInfoTick(_Symbol, attemptTick)) return false;
   datetime now = TimeCurrent();
   double attemptPrice = (orderType == ORDER_TYPE_BUY ? attemptTick.ask : attemptTick.bid);
   datetime previousTime = (orderType == ORDER_TYPE_BUY ? lastBuyAttemptTime : lastSellAttemptTime);
   double previousPrice = (orderType == ORDER_TYPE_BUY ? lastBuyAttemptPrice : lastSellAttemptPrice);
   double minMove = MathMax(SymbolInfoDouble(_Symbol, SYMBOL_POINT), PipSize() * 0.1);

   if(previousTime == now && MathAbs(attemptPrice - previousPrice) < minMove)
   {
      currentStatus = "DUPLICATE ORDER SUPPRESSED";
      blockingReason = "An identical order attempt was already made on this tick/second";
      return false;
   }

   if(orderType == ORDER_TYPE_BUY)
   {
      lastBuyAttemptTime = now;
      lastBuyAttemptPrice = attemptPrice;
   }
   else
   {
      lastSellAttemptTime = now;
      lastSellAttemptPrice = attemptPrice;
   }

   string validationReason;
   if(!CanOpenPosition(orderType, volume, validationReason))
   {
      currentStatus = "ORDER BLOCKED";
      blockingReason = validationReason;
      lastAction = validationReason;
      return false;
   }

   trade.SetExpertMagicNumber(InpMagicNumber);
   trade.SetDeviationInPoints(InpSlippagePoints);

   bool ok = false;
   if(orderType == ORDER_TYPE_BUY)
      ok = trade.Buy(volume, _Symbol, 0.0, 0.0, 0.0, comment);
   else if(orderType == ORDER_TYPE_SELL)
      ok = trade.Sell(volume, _Symbol, 0.0, 0.0, 0.0, comment);

   if(ok)
   {
      lastAction = StringFormat("Opened %s %.2f lot",
                  orderType == ORDER_TYPE_BUY ? "BUY" : "SELL", volume);
   }
   else
   {
      lastAction = StringFormat("Order failed: %d %s",
                  trade.ResultRetcode(), trade.ResultRetcodeDescription());
   }
   return ok;
}

void ManageSingleTradeTP(ENUM_POSITION_TYPE type)
{

   if(CountGridLevels(type) != 1) return;

   MqlTick tick;
   if(!SymbolInfoTick(_Symbol, tick)) return;

   double entry = WeightedAverageEntry(type);
   double pips = 0.0;

   if(type == POSITION_TYPE_BUY)
      pips = (tick.bid - entry) / PipSize();
   else
      pips = (entry - tick.ask) / PipSize();

   if(pips >= InpSingleTradeTPPips)
   {
      ClosePositionsByType(type, "SINGLE TRADE TAKE PROFIT");
      currentStatus = "SINGLE TRADE TP CLOSED";
   }
}

void ManageBasketProfit(ENUM_POSITION_TYPE type)
{
   int count = CountGridLevels(type);
   if(count < 2) return;

   double net = BasketNet(type);
   if(net >= InpBasketProfitTargetMoney)
   {
      ClosePositionsByType(type, "BASKET PROFIT TARGET");
      currentStatus = "BASKET TARGET CLOSED";
   }
}

void ManageGrid(ENUM_POSITION_TYPE type)
{
   int count = CountGridLevels(type);
   if(count <= 0 || count >= InpMaxPositionsPerDirection) return;

   MqlTick tick;
   if(!SymbolInfoTick(_Symbol, tick)) return;

   double newest = (isNettingAccount ? LastEntryDealPrice(type) : NewestEntry(type));
   if(newest <= 0.0) newest = WeightedAverageEntry(type);
   if(newest <= 0.0) return;

   double distancePips = 0.0;
   if(type == POSITION_TYPE_BUY)
      distancePips = (newest - tick.ask) / PipSize();
   else
      distancePips = (tick.bid - newest) / PipSize();

   if(distancePips >= InpGridDistancePips)
   {
      double lot = NextLot(type);
      b

Показано первые 50% кода (символов: 28199)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
2 819,90₽ ≈ $34.46