positionplanningtool.mq5
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «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? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.