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

positionplanningtool.mq5

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

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

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

О программе

PositionPlanningTool — это торговый советник для MetaTrader 5, предназначенный для визуального планирования позиций на графике. Он отображает три перетаскиваемые горизонтальные линии: вход в позицию, стоп-лосс и тейк-профит, а также информационную панель с ключевыми параметрами плана.

Советник автоматически рассчитывает уровни входа, стоп-лосса и тейк-профита на основе выбранного типа ордера и индикатора ATR. Для рыночных ордеров линия входа синхронизируется с актуальными ценами Bid/Ask при каждом тике.

Панель показывает текущий символ, тип ордера, направление, цены уровней, расстояния в пунктах, процент риска, сумму риска, расчётный размер позиции, ожидаемую прибыль и соотношение риск/прибыль (RR). При перетаскивании линий план пересчитывается в реальном времени.

Внутренние расчёты включают определение размера лота на основе процентного риска от баланса счёта и расстояния стоп-лосса, нормализацию объёма по правилам брокера и оценку потенциальной прибыли по соотношению риск/прибыль.

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

НастройкаОписание
InpOrderType Тип ордера для планирования: Buy Market, Sell Market, Buy Limit, Sell Limit, Buy Stop или Sell Stop.
InpRiskPercent Процент от баланса счёта, используемый для расчёта денежного риска и размера позиции.
InpEntryLineColor Цвет горизонтальной линии входа в позицию на графике.
InpSLLineColor Цвет горизонтальной линии стоп-лосса на графике.
InpTPLineColor Цвет горизонтальной линии тейк-профита на графике.
InpATRTimeframe Таймфрейм, на котором рассчитывается значение индикатора ATR для планирования уровней.
InpATRPeriod Период индикатора ATR, используемого для определения расстояния стоп-лосса и тейк-профита.
InpSLATRFactor Множитель ATR, определяющий расстояние стоп-лосса от уровня входа в пунктах цены.
InpTPATRFactor Множитель ATR, определяющий расстояние тейк-профита от уровня входа в пунктах цены.
Получить полный код

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

#property version   "1.00"

#define ENTRY_LINE_NAME "PPT_Entry_Line"
#define SL_LINE_NAME    "PPT_StopLoss_Line"
#define TP_LINE_NAME    "PPT_TakeProfit_Line"

#define PANEL_PREFIX    "PPT_Panel_"

#define PANEL_BG_NAME   "PPT_Panel_Background"

#define PANEL_X         20
#define PANEL_Y         30
#define PANEL_WIDTH     280
#define PANEL_HEIGHT    285
#define PANEL_LINE_GAP  18

#define PANEL_TEXT      clrWhite
#define PANEL_TITLE     clrGold
#define PANEL_BG        clrBlack
#define PANEL_BORDER    clrDimGray

enum ENUM_POSITION_TOOL_ORDER_TYPE
  {
   PTO_BUY_MARKET = 0,    // Buy Market
   PTO_SELL_MARKET,       // Sell Market
   PTO_BUY_LIMIT,         // Buy Limit
   PTO_SELL_LIMIT,        // Sell Limit
   PTO_BUY_STOP,          // Buy Stop
   PTO_SELL_STOP          // Sell Stop
  };

enum ENUM_POSITION_TOOL_DIRECTION
  {
   PTD_BUY = 0,           // Buy setup
   PTD_SELL               // Sell setup
  };

input ENUM_POSITION_TOOL_ORDER_TYPE InpOrderType       = PTO_BUY_MARKET;
input double                        InpRiskPercent      = 1.0;
input color                         InpEntryLineColor   = clrDodgerBlue;
input color                         InpSLLineColor      = clrTomato;
input color                         InpTPLineColor      = clrLimeGreen;

input ENUM_TIMEFRAMES InpATRTimeframe = PERIOD_H1;
input int             InpATRPeriod    = 14;
input double          InpSLATRFactor  = 1.0;
input double          InpTPATRFactor  = 2.0;

double EntryPrice      = 0.0;
double StopLossPrice   = 0.0;
double TakeProfitPrice = 0.0;

ENUM_POSITION_TOOL_DIRECTION GetSetupDirection()
  {

   switch(InpOrderType)
     {
      case PTO_BUY_MARKET:
      case PTO_BUY_LIMIT:
      case PTO_BUY_STOP:
         return PTD_BUY;

      case PTO_SELL_MARKET:
      case PTO_SELL_LIMIT:
      case PTO_SELL_STOP:
         return PTD_SELL;
     }

   return PTD_BUY;
  }

int OnInit()
  {
      // код доступен только после оплаты
   }

void OnDeinit(const int reason)
  {

   if(!DeleteDashboard())
      Print("Warning: One or more dashboard objects could not be deleted.");

   if(!DeletePositionLines())
      Print("Warning: One or more planning lines could not be deleted.");

   ChartRedraw(0);
  }

void OnTick()
  {
      // код доступен только после оплаты
   }

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {

   if(id != CHARTEVENT_OBJECT_DRAG)
      return;

   if(IsMarketOrderType() && sparam == ENTRY_LINE_NAME)
      return;

   if(sparam == ENTRY_LINE_NAME ||
      sparam == SL_LINE_NAME ||
      sparam == TP_LINE_NAME)
     {

      if(!UpdateDashboard())
         Print("Failed to update the dashboard after line movement.");
     }
  }

void PrintApiError(const string functionName,const string context)
  {

   Print(functionName," failed while ",context,". Error: ",GetLastError());
  }

bool GetATRValue(double &atr)
  {

   atr = 0.0;

   ResetLastError();

   int handle = iATR(_Symbol,InpATRTimeframe,InpATRPeriod);

   if(handle == INVALID_HANDLE)
     {

      PrintApiError("iATR()","creating the ATR indicator handle");
      return false;
     }

   double buffer[];

   ResetLastError();

   int copied = CopyBuffer(handle,0,0,1,buffer);

   if(copied < 1)
     {

      PrintApiError("CopyBuffer()","reading the ATR value");

      ResetLastError();

      if(!IndicatorRelease(handle))
         PrintApiError("IndicatorRelease()",
                       "releasing the ATR handle after CopyBuffer() failure");

      return false;
     }

   atr = buffer[0];

   ResetLastError();

   if(!IndicatorRelease(handle))
     {
      PrintApiError("IndicatorRelease()",
                    "releasing the ATR indicator handle");
      return false;
     }

   return true;
  }

bool GetSymbolDoubleProperty(const ENUM_SYMBOL_INFO_DOUBLE property,
                             double &value)
  {
   ResetLastError();

   if(!SymbolInfoDouble(_Symbol,property,value))
     {

      PrintApiError("SymbolInfoDouble()",
                    "reading symbol data for " + _Symbol);
      return false;
     }

   return true;
  }

bool InitializeLinePrices()
  {
   double bid = 0.0;
   double ask = 0.0;

   if(!GetSymbolDoubleProperty(SYMBOL_BID,bid))
      return false;

   if(!GetSymbolDoubleProperty(SYMBOL_ASK,ask))
      return false;

   double atr = 0.0;

   if(!GetATRValue(atr) || atr <= 0.0)
     {

      atr = 100 * _Point;
      Print("ATR unavailable. Using a fallback distance of 100 points.");
     }

   double slDistance = atr * InpSLATRFactor;
   double tpDistance = atr * InpTPATRFactor;

   switch(InpOrderType)
     {
      case PTO_BUY_MARKET:

         EntryPrice      = ask;
         StopLossPrice   = EntryPrice - slDistance;
         TakeProfitPrice = EntryPrice + tpDistance;
         break;

      case PTO_SELL_MARKET:

         EntryPrice      = bid;
         StopLossPrice   = EntryPrice + slDistance;
         TakeProfitPrice = EntryPrice - tpDistance;
         break;

      case PTO_BUY_LIMIT:

         EntryPrice      = bid - slDistance;
         StopLossPrice   = EntryPrice - slDistance;
         TakeProfitPrice = EntryPrice + tpDistance;
         break;

      case PTO_SELL_LIMIT:

         EntryPrice      = ask + slDistance;
         StopLossPrice   = EntryPrice + slDistance;
         TakeProfitPrice = EntryPrice - tpDistance;
         break;

      case PTO_BUY_STOP:

         EntryPrice      = ask + slDistance;
         StopLossPrice   = EntryPrice - slDistance;
         TakeProfitPrice = EntryPrice + tpDistance;
         break;

      case PTO_SELL_STOP:

         EntryPrice      = bid - slDistance;
         StopLossPrice   = EntryPrice + slDistance;
         TakeProfitPrice = EntryPrice - tpDistance;
         break;
     }

   return true;
  }

bool DeleteObjectIfExists(const string name)
  {

   if(ObjectFind(0,name) < 0)
      return true;

   ResetLastError();

   if(!ObjectDelete(0,name))
     {
      PrintApiError("ObjectDelete()","deleting object '" + name + "'");
      return false;
     }

   return true;
  }

bool SetObjectIntegerProperty(const string name,
                              const ENUM_OBJECT_PROPERTY_INTEGER property,
                              const long value)
  {
   ResetLastError();

   if(!ObjectSetInteger(0,name,property,value))
     {

      PrintApiError("ObjectSetInteger()",
                    "setting a property on '" + name + "'");
      return false;
     }

   return true;
  }

bool SetObjectStringProperty(const string name,
                             const ENUM_OBJECT_PROPERTY_STRING property,
                             const string value)
  {
   ResetLastError();

   if(!ObjectSetString(0,name,property,value))
     {

      PrintApiError("ObjectSetString()",
                    "setting a property on '" + name + "'");
      return false;
     }

   return true;
  }

bool IsMarketOrderType()
  {

   return InpOrderType == PTO_BUY_MARKET ||
          InpOrderType == PTO_SELL_MARKET;
  }

bool CreatePriceLine(const string name,
                     const double price,
                     const color lineColor,
                     const string text)
  {

   if(!DeleteObjectIfExists(name))
      return false;

   ResetLastError();

   if(!ObjectCreate(0,name,OBJ_HLINE,0,0,price))
     {
      PrintApiError("ObjectCreate()","creating line '" + name + "'");
      return false;
     }

   bool draggable = true;

   if(name == ENTRY_LINE_NAME && IsMarketOrderType())
      draggable = false;

   ResetLastError();

   if(!ObjectMove(0,name,0,0,price))
     {
      PrintApiError("ObjectMove()","positioning line '" + name + "'");
      return false;
     }

   if(!SetObjectIntegerProperty(name,OBJPROP_COLOR,lineColor))
      return false;

   if(!SetObjectIntegerProperty(name,OBJPROP_WIDTH,2))
      return false;

   if(!SetObjectIntegerProperty(name,OBJPROP_STYLE,STYLE_SOLID))
      return false;

   if(!SetObjectIntegerProperty(name,OBJPROP_BACK,false))
      return false;

   if(!SetObjectIntegerProperty(name,OBJPROP_SELECTABLE,draggable))
      return false;

   if(!SetObjectIntegerProperty(name,OBJPROP_SELECTED,draggable))
      return false;

   if(!SetObjectIntegerProperty(name,OBJPROP_HIDDEN,false))
      return false;

   if(!SetObjectStringProperty(name,OBJPROP_TEXT,text))
      return false;

   return true;
  }

bool CreatePositionLines()
  {

   if(!CreatePriceLine(ENTRY_LINE_NAME,EntryPrice,
                       InpEntryLineColor,"Entry"))
      return false;

   if(!CreatePriceLine(SL_LINE_NAME,StopLossPrice,
                       InpSLLineColor,"Stop Loss"))
      return false;

   if(!CreatePriceLine(TP_LINE_NAME,TakeProfitPrice,
                       InpTPLineColor,"Take Profit"))
      return false;

   ChartRedraw(0);

   return true;
  }

bool GetLinePrice(const string name,double &price)
  {

   if(ObjectFind(0,name) < 0)
     {
      Print("Object not found: ",name);
      return false;
     }

   ResetLastError();

   if(!ObjectGetDouble(0,name,OBJPROP_PRICE,0,price))
     {

      PrintApiError("ObjectGetDouble()",
                    "reading price from '" + name + "'");
      return false;
     }

   return true;
  }

bool UpdateLinePrices()
  {

   if(!GetLinePrice(ENTRY_LINE_NAME,EntryPrice))
      return false;

   if(!GetLinePrice(SL_LINE_NAME,StopLossPrice))
      return false;

   if(!GetLinePrice(TP_LINE_NAME,TakeProfitPrice))
      return false;

   return true;
  }

bool UpdateMarketEntryPrice()
  {

   if(!IsMarketOrderType())
      return true;

   if(InpOrderType == PTO_BUY_MARKET)
     {
      if(!GetSymbolDoubleProperty(SYMBOL_ASK,EntryPrice))
         return false;
     }
   else

      if(InpOrderType == PTO_SELL_MARKET)
        {
         if(!GetSymbolDoubleProperty(SYMBOL_BID,EntryPrice))
            return false;
        }

   ResetLastError();

   if(!ObjectMove(0,ENTRY_LINE_NAME,0,0,EntryPrice))
     {
      PrintApiError("ObjectMove()",
                    "updating the market Entry line");
      return false;
     }

   return true;
  }

bool ValidateLineStructure(string &status)
  {

   ENUM_POSITION_TOOL_DIRECTION direction = GetSetupDirection();

   if(EntryPrice == StopLossPrice)
     {
      status = "Invalid: Entry and Stop-Loss cannot be equal.";
      return false;
     }

   if(direction == PTD_BUY)
     {
      if(StopLossPrice >= EntryPrice)
        {
         status = "Invalid: Buy setup requires Stop-Loss below Entry.";
         return false;
        }

      if(TakeProfitPrice <= EntryPrice)
        {
         status = "Invalid: Buy setup requires Take-Profit above Entry.";
         return false;
        }
     }

   if(direction == PTD_SELL)
     {
      if(StopLossPrice <= EntryPrice)
        {
         status = "Invalid: Sell setup requires Stop-Loss above Entry.";
         return false;
        }

      if(TakeProfitPrice >= EntryPrice)
        {
         status = "Invalid: Sell setup requires Take-Profit below Entry.";
         return false;
        }
     }

   status = "Valid setup.";
   return true;
  }

bool CalculateStopLossDistance(double &stopDistance,
                               double &stopPoints,
                               string &status)
  {

   stopDistance = MathAbs(EntryPrice - StopLossPrice);

   stopPoints = stopDistance / _Point;

   if(stopDistance <= 0.0)
     {
      status = "Invalid: Stop-Loss distance must be greater than zero.";
      return false;
     }

   status = "Valid Stop-Loss distance.";
   return true;
  }

bool CalculateRiskAmount(double &riskMoney,string &status)
  {

   double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);

   if(accountBalance <= 0.0)
     {
      status = "Invalid: Account balance must be greater than zero.";
      return false;
     }

   if(InpRiskPercent <= 0.0)
     {
      status = "Invalid: Risk percentage must be greater than zero.";
      return false;
     }

   riskMoney = accountBalance * InpRiskPercent / 100.0;

   if(riskMoney <= 0.0)
     {
      status = "Invalid: Calculated risk amount must be greater than zero.";
      return false;
     }

   status = "Risk amount calculated.";
   return true;
  }

int GetVolumeDigits(const double volumeStep)
  {
   int digits = 0;
   double step = volumeStep;

   while(digits < 8 && MathAbs(step - MathRound(step)) > 1e-8)
     {
      step *= 10.0;
      digits++;
     }

   return digits;
  }

bool NormalizeVolume(const double volume,
                     double &normalizedVolume,
                     string &status)
  {
   double minVolume  = 0.0;
   double maxVolume  = 0.0;
   double volumeStep = 0.0;

   if(!GetSymbolDoubleProperty(SYMBOL_VOLUME_MIN,minVolume))
     {
      status = "Invalid: Minimum volume is unavailable.";
      return false;
     }

   if(!GetSymbolDoubleProperty(SYMBOL_VOLUME_MAX,maxVolume))
     {
      status = "Invalid: Maximum volume is unavailable.";
      return false;
     }

   if(!GetSymbolDoubleProperty(SYMBOL_VOLUME_STEP,volumeStep))
     {
      status = "Invalid: Vol

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

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

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

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

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

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

Стоимость полного кода
1 811₽ ≈ $22.14