313 lines
25 KiB
MQL5
313 lines
25 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Virtual Trailing Stop(barabashkakvn's edition).mq5 |
|
|
//| Copyright 2015, cmillion |
|
|
//| http://cmillion.ru |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright © 2015, cmillion@narod.ru"
|
|
#property link "http://cmillion.ru"
|
|
//---
|
|
#include <Trade\PositionInfo.mqh>
|
|
#include <Trade\Trade.mqh>
|
|
#include <Trade\SymbolInfo.mqh>
|
|
CPositionInfo m_position; // trade position object
|
|
CTrade m_trade; // trading object
|
|
CSymbolInfo m_symbol; // symbol info object
|
|
//--- input parameters
|
|
input ushort Stoploss = 0;
|
|
input ushort Takeprofit = 0;
|
|
input ushort TrailingStop = 5;
|
|
input ushort TrailingStart = 5;
|
|
input ushort TrailingStep = 1;
|
|
//--- HLine
|
|
input string InpNameBuy = "SL Buy"; // BUY Line name
|
|
input string InpNameSell = "SL Sell"; // SELL Line name
|
|
input ENUM_LINE_STYLE InpStyle=STYLE_DASHDOTDOT; // Line style
|
|
//---
|
|
ulong m_slippage=10; // slippage
|
|
double TrallB = 0;
|
|
double TrallS = 0;
|
|
|
|
double ExtStoploss=0.0;
|
|
double ExtTakeprofit=0.0;
|
|
double ExtTrailingStop=0.0;
|
|
double ExtTrailingStart=0.0;
|
|
double ExtTrailingStep=0.0;
|
|
|
|
double m_adjusted_point; // point value adjusted for 3 or 5 points
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
if(!m_symbol.Name(Symbol())) // sets symbol name
|
|
return(INIT_FAILED);
|
|
RefreshRates();
|
|
//---
|
|
m_trade.SetMarginMode();
|
|
m_trade.SetTypeFillingBySymbol(m_symbol.Name());
|
|
m_trade.SetDeviationInPoints(m_slippage);
|
|
//--- tuning for 3 or 5 digits
|
|
int digits_adjust=1;
|
|
if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
|
|
digits_adjust=10;
|
|
m_adjusted_point=m_symbol.Point()*digits_adjust;
|
|
|
|
ExtStoploss = Stoploss * m_adjusted_point;
|
|
ExtTakeprofit = Takeprofit * m_adjusted_point;
|
|
ExtTrailingStop = TrailingStop * m_adjusted_point;
|
|
ExtTrailingStart = TrailingStart * m_adjusted_point;
|
|
ExtTrailingStep = TrailingStep * m_adjusted_point;
|
|
//---
|
|
if(!HLineCreate(0,InpNameBuy,0,0,clrBlue,InpStyle) || !HLineCreate(0,InpNameSell,0,0,clrRed,InpStyle))
|
|
return(INIT_FAILED);
|
|
//---
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//---
|
|
HLineDelete(0,InpNameBuy);
|
|
HLineDelete(0,InpNameSell);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//---
|
|
int b=0,s=0;
|
|
ulong TicketB=0,TicketS=0;
|
|
for(int i=PositionsTotal()-1;i>=0;i--)
|
|
if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
|
|
if(m_position.Symbol()==m_symbol.Name())
|
|
{
|
|
if(!RefreshRates())
|
|
return;
|
|
if(m_position.PositionType()==POSITION_TYPE_BUY)
|
|
{
|
|
b++;
|
|
|
|
TicketB=m_position.Ticket();
|
|
if(TrailingStop>0)
|
|
{
|
|
double SL=m_symbol.Bid()-ExtTrailingStop;
|
|
if(SL>=m_position.PriceOpen()+ExtTrailingStart && (TrallB==0 || TrallB+ExtTrailingStep<SL))
|
|
TrallB=SL;
|
|
}
|
|
}
|
|
if(m_position.PositionType()==POSITION_TYPE_SELL)
|
|
{
|
|
s++;
|
|
|
|
TicketS=m_position.Ticket();
|
|
if(TrailingStop>0)
|
|
{
|
|
double SL=m_symbol.Ask()+ExtTrailingStop;
|
|
if(SL<=m_position.PriceOpen()-ExtTrailingStart && (TrallS==0 || TrallS-ExtTrailingStep>SL))
|
|
TrallS=SL;
|
|
}
|
|
}
|
|
}
|
|
//---
|
|
if(b!=0)
|
|
{
|
|
if(b>1)
|
|
Comment("Трал корректно работает только с одной позицией");
|
|
else
|
|
if(TrallB!=0)
|
|
{
|
|
Comment("Тралим позицию ",TicketB);
|
|
HLineMove(0,InpNameBuy,TrallB);
|
|
if(m_symbol.Bid()<=TrallB)
|
|
{
|
|
if(m_position.SelectByTicket(TicketB))
|
|
if(m_position.Profit()>0.0)
|
|
if(!m_trade.PositionClose(TicketB))
|
|
Comment("Ошибка закрытия позиции. Result Retcode: ",m_trade.ResultRetcode(),
|
|
", description of result: ",m_trade.ResultRetcodeDescription());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TrallB=0;
|
|
HLineMove(0,InpNameBuy,0.1);
|
|
}
|
|
//---
|
|
if(s!=0)
|
|
{
|
|
if(s>1)
|
|
Comment("Трал корректно работает только с одной позицией");
|
|
else
|
|
if(TrallS!=0)
|
|
{
|
|
Comment("Тралим позицию ",TicketS);
|
|
HLineMove(0,InpNameSell,TrallS);
|
|
if(m_symbol.Ask()>=TrallS)
|
|
{
|
|
if(m_position.SelectByTicket(TicketS))
|
|
if(m_position.Profit()>0.0)
|
|
if(!m_trade.PositionClose(TicketS))
|
|
Comment("Ошибка закрытия позиции. Result Retcode: ",m_trade.ResultRetcode(),
|
|
", description of result: ",m_trade.ResultRetcodeDescription());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TrallS=0;
|
|
HLineMove(0,InpNameSell,0.1);
|
|
}
|
|
//---
|
|
/*
|
|
MQL_PROFILER
|
|
The flag, that indicates the program operating in the code profiling mode
|
|
|
|
MQL_TESTER
|
|
The flag, that indicates the tester process
|
|
|
|
MQL_OPTIMIZATION
|
|
The flag, that indicates the optimization process
|
|
|
|
MQL_VISUAL_MODE
|
|
The flag, that indicates the visual tester process
|
|
*/
|
|
if((MQLInfoInteger(MQL_PROFILER) || MQLInfoInteger(MQL_TESTER) ||
|
|
MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_VISUAL_MODE)) && !IsPositionExists())
|
|
{
|
|
m_trade.Buy(m_symbol.LotsMin(),m_symbol.Name());
|
|
m_trade.Sell(m_symbol.LotsMin(),m_symbol.Name());
|
|
}
|
|
//---
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| TradeTransaction function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTradeTransaction(const MqlTradeTransaction &trans,
|
|
const MqlTradeRequest &request,
|
|
const MqlTradeResult &result)
|
|
{
|
|
//---
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Create the horizontal line |
|
|
//+------------------------------------------------------------------+
|
|
bool HLineCreate(const long chart_ID=0, // chart's ID
|
|
const string name="HLine", // line name
|
|
const int sub_window=0, // subwindow index
|
|
double price=0, // line price
|
|
const color clr=clrRed, // line color
|
|
const ENUM_LINE_STYLE style=STYLE_SOLID, // line style
|
|
const int width=1, // line width
|
|
const bool back=false, // in the background
|
|
const bool selection=false, // highlight to move
|
|
const bool hidden=true, // hidden in the object list
|
|
const long z_order=0) // priority for mouse click
|
|
{
|
|
//--- if the price is not set, set it at the current Bid price level
|
|
if(!price)
|
|
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
|
|
//--- reset the error value
|
|
ResetLastError();
|
|
//--- create a horizontal line
|
|
if(!ObjectCreate(chart_ID,name,OBJ_HLINE,sub_window,0,price))
|
|
{
|
|
Print(__FUNCTION__,
|
|
": failed to create a horizontal line! Error code = ",GetLastError());
|
|
return(false);
|
|
}
|
|
//--- set line color
|
|
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
|
|
//--- set line display style
|
|
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
|
|
//--- set line width
|
|
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
|
|
//--- display in the foreground (false) or background (true)
|
|
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
|
|
//--- enable (true) or disable (false) the mode of moving the line by mouse
|
|
//--- when creating a graphical object using ObjectCreate function, the object cannot be
|
|
//--- highlighted and moved by default. Inside this method, selection parameter
|
|
//--- is true by default making it possible to highlight and move the object
|
|
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
|
|
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
|
|
//--- hide (true) or display (false) graphical object name in the object list
|
|
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
|
|
//--- set the priority for receiving the event of a mouse click in the chart
|
|
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
|
|
//--- successful execution
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Move horizontal line |
|
|
//+------------------------------------------------------------------+
|
|
bool HLineMove(const long chart_ID=0, // chart's ID
|
|
const string name="HLine", // line name
|
|
double price=0) // line price
|
|
{
|
|
//--- if the line price is not set, move it to the current Bid price level
|
|
if(!price)
|
|
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
|
|
//--- reset the error value
|
|
ResetLastError();
|
|
//--- move a horizontal line
|
|
if(!ObjectMove(chart_ID,name,0,0,price))
|
|
{
|
|
Print(__FUNCTION__,
|
|
": failed to move the horizontal line! Error code = ",GetLastError());
|
|
return(false);
|
|
}
|
|
//--- successful execution
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Delete a horizontal line |
|
|
//+------------------------------------------------------------------+
|
|
bool HLineDelete(const long chart_ID=0, // chart's ID
|
|
const string name="HLine") // line name
|
|
{
|
|
//--- reset the error value
|
|
ResetLastError();
|
|
//--- delete a horizontal line
|
|
if(!ObjectDelete(chart_ID,name))
|
|
{
|
|
Print(__FUNCTION__,
|
|
": failed to delete a horizontal line! Error code = ",GetLastError());
|
|
return(false);
|
|
}
|
|
//--- successful execution
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Refreshes the symbol quotes data |
|
|
//+------------------------------------------------------------------+
|
|
bool RefreshRates(void)
|
|
{
|
|
//--- refresh rates
|
|
if(!m_symbol.RefreshRates())
|
|
{
|
|
Print("RefreshRates error");
|
|
return(false);
|
|
}
|
|
//--- protection against the return value of "zero"
|
|
if(m_symbol.Ask()==0 || m_symbol.Bid()==0)
|
|
return(false);
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Is position exists |
|
|
//+------------------------------------------------------------------+
|
|
bool IsPositionExists(void)
|
|
{
|
|
for(int i=PositionsTotal()-1;i>=0;i--)
|
|
if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
|
|
if(m_position.Symbol()==m_symbol.Name())
|
|
return(true);
|
|
//---
|
|
return(false);
|
|
}
|
|
//+------------------------------------------------------------------+
|