Article-20147-MQL5-Terminal.../ExpWPRBB.mq5

878 lines
78 KiB
MQL5
Raw Permalink Normal View History

2026-03-26 17:44:46 +07:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| ExpWPRBB.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| :;NG05<K5 D09;K |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <Arrays\ArrayLong.mqh>
//+------------------------------------------------------------------+
//| 5@5G8A;5=8O |
//+------------------------------------------------------------------+
//--- "8?K A83=0;>2
enum ENUM_SIGNAL_TYPE
{
SIGNAL_TYPE_NONE, // 5B A83=0;0
SIGNAL_TYPE_LONG, // !83=0; =0 ?>:C?:C
SIGNAL_TYPE_SHORT, // !83=0; =0 ?>:C?:C
};
//--- !B@C:BC@0 ?>78F89
struct SData
{
CArrayLong list_tickets; // !?8A>: B8:5B>2 >B:@KBKE ?>78F89
double total_volume; // 1I89 >1JQ< >B:@KBKE ?>78F89
};
//--- !B@C:BC@0 40==KE ?>78F89 ?> B8?0<
struct SDataPositions
{
SData Buy; // 0==K5 ?>78F89 Buy
SData Sell; // 0==K5 ?>78F89 Sell
}
Data;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 0:@>?>4AB0=>2:8 |
//+------------------------------------------------------------------+
#define DATA_COUNT 3 // >;8G5AB2> ?>;CG05<KE 40==KE >B 8=48:0B>@>2 (3 8 1>;55)
#define ENV_ATTEMPTS 3 // >;8G5AB2> ?>?KB>: >6840=8O ?>;CG5=8O >:@C65=8O
#define ENV_WAIT_ATTEMPT 1000 // >;8G5AB2> <8;;8A5:C=4 >6840=8O >1=>2;5=8O >:@C65=8O
#define SPREAD_MLTP 3 // =>68B5;L A?@540 4;O 48AB0=F88 AB>?-?@8:07>2
//+------------------------------------------------------------------+
//| E>4=K5 ?0@0<5B@K |
//+------------------------------------------------------------------+
//--- WPR
input int InpPeriodWPR = 32; /* WPR calculation period */ // 5@8>4 @0AGQB0 WPR
input double InpOverboughtWPR = -20; /* WPR Overbought Level */ // #@>25=L ?5@5:C?;5==>AB8 WPR
input double InpOversoldWPR = -80; /* WPR Oversold Level */ // #@>25=L ?5@5?@>40==>AB8 WPR
//--- BB
input int InpPeriodBB = 58; /* BB calculation period */ // 5@8>4 @0AGQB0 BB
input double InpDeviationBB = 2.0; /* BB deviations */ // B:;>=5=8O BB
input int InpShiftBB = 0; /* BB shift */ // !4283 BB
input ENUM_APPLIED_PRICE InpPriceBB = PRICE_CLOSE; /* BB applied price */ // &5=0 @0AGQB0 BB
//--- ATR
input int InpPeriodATR = 64; /* ATR calculation period */ // 5@8>4 @0AGQB0 ATR
//--- ">@3>2;O
input bool InpSignalsOnly = false; /* Don't trade, just mark signals */ // 5 B>@3>20BL, B>;L:> AB028BL <5B:8 A83=0;>2
input double InpVolume = 0.1; /* Position volume */ // 1J5< ?>78F88
sinput ulong InpDeviation = 10; /* Slippage (in points) */ // @>A:0;L7K20=85 (2 ?C=:B0E)
sinput ulong InpMagic = 123456; /* Magic number */ // 038:
input int InpStopLoss = -1; /* Stop loss (in points), 0 - none, -1 - half of BB */ // Stop loss (2 ?C=:B0E), 0 - >BACBAB2C5B, -1 - ?>;>28=0 BB
input int InpTakeProfit = -1; /* Take profit (in points), 0 - none, -1 - ATR value */ // Take profit (2 ?C=:B0E), 0 - >BACBAB2C5B, -1 - 7=0G5=85 ATR
input double InpSLMltp = 2.6; /* Stop loss size multiplier, if SL==-1 */ // =>68B5;L @07<5@0 Stop loss, 5A;8 Stop loss==-1
input double InpTPMltp = 1.3; /* Take profit size multiplier, if TP==-1 */ // =>68B5;L @07<5@0 Take profit, 5A;8 Take profit==-1
//+------------------------------------------------------------------+
//| ;>10;L=K5 ?5@5<5==K5 |
//+------------------------------------------------------------------+
CTrade trade; // 1J5:B B>@3>2>3> :;0AA0
int handle_wpr; // %M=4; 8=48:0B>@0 WPR
int handle_bb; // %M=4; 8=48:0B>@0 BB
int handle_atr; // %M=4; 8=48:0B>@0 ATR
double wpr[DATA_COUNT]={}; // 0AA82 7=0G5=89 WPR
double bb0[DATA_COUNT]={}; // 0AA82 7=0G5=89 BB, 1CD5@ 0 (Upper)
double bb1[DATA_COUNT]={}; // 0AA82 7=0G5=89 BB, 1CD5@ 1 (Lower)
double bb2[DATA_COUNT]={}; // 0AA82 7=0G5=89 BB, 1CD5@ 2 (Middle)
double atr[DATA_COUNT]={}; // 0AA82 7=0G5=89 ATR
MqlRates prc[DATA_COUNT]={}; // 0AA82 F5= 8 2@5<5=8
int period_wpr; // 5@8>4 @0AGQB0 WPR
double overbought_wpr; // #@>25=L ?5@5:5C?;5==>AB8 WPR
double oversold_wpr; // #@>25=L ?5@5?@>40==>AB8 WPR
int period_bb; // 5@8>4 @0AGQB0 BB
double deviation_bb; // B:;>=5=8O BB
int shift_bb; // !4283 BB
int period_atr; // 5@8>4 @0AGQB0 ATR
double lot; // 1JQ< ?>78F88
string program_name; // <O ?@>3@0<<K
int prev_total; // >;8G5AB2> ?>78F89 =0 ?@>H;>9 ?@>25@:5
bool netto; // @87=0: =5BB>-AGQB0
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- A;8 AGQB =5 A B8?>< E5468=3 - AB028< D;03 8 A>>1I05< > =5:>@@5:B=>9 @01>B5 A>25B=8:0
netto=false;
if(AccountInfoInteger(ACCOUNT_MARGIN_MODE)!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
{
Print("The advisor is designed for use on a hedging account. Correct operation on a netting account is not guaranteed.");
netto=true;
}
//--- #AB0=02;8205< 8 :>@@5:B8@C5< 2E>4=K5 ?5@5<5==K5 8=48:0B>@>2
//--- WPR
period_wpr=(InpPeriodWPR<1 ? 14 : InpPeriodWPR);
overbought_wpr=(InpOverboughtWPR<-99 ? -99 : InpOverboughtWPR> 0 ? 0 : InpOverboughtWPR);
oversold_wpr =(InpOversoldWPR <-100 ? -100 : InpOversoldWPR >-1 ? -1 : InpOversoldWPR);
if(overbought_wpr<=oversold_wpr)
overbought_wpr+=1;
//--- BB
period_bb=(InpPeriodBB<2 ? 20 : InpPeriodBB);
deviation_bb=InpDeviationBB;
shift_bb=InpShiftBB;
//--- ATR
period_atr=(InpPeriodATR<1 ? 14 : InpPeriodATR);
//--- =8F80;878@C5< <0AA82K 7=0G5=89 8=48:0B>@>2
ArrayInitialize(wpr,EMPTY_VALUE);
ArrayInitialize(bb0,EMPTY_VALUE);
ArrayInitialize(bb1,EMPTY_VALUE);
ArrayInitialize(bb2,EMPTY_VALUE);
ZeroMemory(prc);
//--- !>740Q< EM=4;K 8=48:0B>@>2
//--- WPR
handle_wpr=iWPR(Symbol(),PERIOD_CURRENT,period_wpr);
if(handle_wpr==INVALID_HANDLE)
{
PrintFormat("%s: Failed to create iWPR(%d) handle",__FUNCTION__,period_wpr);
return INIT_FAILED;
}
//--- BB
handle_bb=iBands(Symbol(),PERIOD_CURRENT,period_bb,shift_bb,deviation_bb,InpPriceBB);
if(handle_bb==INVALID_HANDLE)
{
PrintFormat("%s: Failed to create iBands(%d,%d,%.3f,%s) handle",__FUNCTION__,period_bb,shift_bb,deviation_bb,EnumToString(InpPriceBB));
return INIT_FAILED;
}
//--- WPR
handle_atr=iATR(Symbol(),PERIOD_CURRENT,period_atr);
if(handle_atr==INVALID_HANDLE)
{
PrintFormat("%s: Failed to create iATR(%d) handle",__FUNCTION__,period_atr);
return INIT_FAILED;
}
//--- <O ?@>3@0<<K 8 :>;8G5AB2> ?>78F89 =0 ?@>H;>9 ?@>25@:5
program_name=MQLInfoString(MQL_PROGRAM_NAME);
prev_total=0;
//--- 2B><0B8G5A:0O CAB0=>2:0 B8?0 70?>;=5=8O
trade.SetTypeFilling(GetTypeFilling());
//--- #AB0=>2:0 <038:0
trade.SetExpertMagicNumber(InpMagic);
//--- #AB0=>2:0 ?@>A:0;L7K20=8O
trade.SetDeviationInPoints(InpDeviation);
//--- #AB0=>2:0 ;>B0 A :>@@5:B8@>2:>9 2254Q==>3> 7=0G5=8O
lot=CorrectLots(InpVolume);
//--- AQ CA?5H=>
PrintFormat("%s::%s: Initialization was successful",program_name,__FUNCTION__);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- >;CG05< 2 <0AA82K 40==K5 B@QE 10@>2 8=48:0B>@>2 8 F5=
if(!CopyIndicatorsData() || !CopyPricesData())
return;
//--- 0?>;=5=85 A?8A:>2 B8:5B>2 ?>78F89
int positions_total=PositionsTotal();
if(prev_total!=positions_total)
{
if(!FillingListTickets(Symbol(),InpMagic))
return;
prev_total=positions_total;
}
//--- >;CG05< A83=0;K >B 8=48:0B>@>2
ENUM_SIGNAL_TYPE signal_wpr=SignalWPR();
ENUM_SIGNAL_TYPE signal_bb=SignalBB();
//--- 1I89 A83=0;
ENUM_SIGNAL_TYPE signal=(signal_wpr==signal_bb ? signal_wpr : SIGNAL_TYPE_NONE);
//--- A;8 =5 B>@3C5< - AB028< <5B:8 A83=0;>2 8=48:0B>@>2
if(InpSignalsOnly)
{
SetArrow(IND_WPR,signal_wpr,false);
SetArrow(IND_BANDS,signal_bb,true);
return;
}
//--- ">@3C5< ?> A83=0;0<
TradeProcess(signal);
}
//+------------------------------------------------------------------+
//| >;CG05B 7=0G5=8O Open 4;O B@QE 10@>2 |
//+------------------------------------------------------------------+
bool CopyPricesData(void)
{
ResetLastError();
if(CopyRates(Symbol(),PERIOD_CURRENT,0,DATA_COUNT,prc)!=DATA_COUNT)
{
PrintFormat("%s: Failed to get price Open data. Error %d",__FUNCTION__,GetLastError());
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| >;CG05B 7=0G5=8O WPR 4;O B@QE 10@>2 |
//+------------------------------------------------------------------+
bool CopyWPRData(void)
{
ResetLastError();
if(CopyBuffer(handle_wpr,0,0,DATA_COUNT,wpr)!=DATA_COUNT)
{
PrintFormat("%s: Failed to get WPR data. Error %d",__FUNCTION__,GetLastError());
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| >;CG05B 7=0G5=8O BB 4;O B@QE 10@>2 |
//+------------------------------------------------------------------+
bool CopyBBData(void)
{
ResetLastError();
if(CopyBuffer(handle_bb,UPPER_BAND,0,DATA_COUNT,bb0)!=DATA_COUNT)
{
PrintFormat("%s: Failed to get BB Upper Line data. Error %d",__FUNCTION__,GetLastError());
return false;
}
if(CopyBuffer(handle_bb,LOWER_BAND,0,DATA_COUNT,bb1)!=DATA_COUNT)
{
PrintFormat("%s: Failed to get BB Lower Line data. Error %d",__FUNCTION__,GetLastError());
return false;
}
if(CopyBuffer(handle_bb,BASE_LINE,0,DATA_COUNT,bb2)!=DATA_COUNT)
{
PrintFormat("%s: Failed to get BB Base Line data. Error %d",__FUNCTION__,GetLastError());
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| >;CG05B 7=0G5=8O ATR 4;O B@QE 10@>2 |
//+------------------------------------------------------------------+
bool CopyATRData(void)
{
ResetLastError();
if(CopyBuffer(handle_atr,0,0,DATA_COUNT,atr)!=DATA_COUNT)
{
PrintFormat("%s: Failed to get ATR data. Error %d",__FUNCTION__,GetLastError());
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| >;CG05B 7=0G5=8O 8=48:0B>@>2 4;O B@QE 10@>2 |
//+------------------------------------------------------------------+
bool CopyIndicatorsData(void)
{
bool res=CopyWPRData(); // 57C;LB0B ?>;CG5=8O 40==KE WPR
res &=CopyBBData(); // 57C;LB0B ?>;CG5=8O 40==KE BB
res &=CopyATRData(); // 57C;LB0B ?>;CG5=8O 40==KE ATR
return res;
}
//+------------------------------------------------------------------+
//| >72@0I05B 87 <0AA820 F5=C Open ?> 8=45:AC B09<A5@88 (0 - 2) |
//+------------------------------------------------------------------+
double PriceOpen(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? 0 : prc[DATA_COUNT-index-1].open);
}
//+------------------------------------------------------------------+
//|>72@0I05B 87 <0AA820 F5=C High ?> 8=45:AC B09<A5@88 (0 - 2)|
//+------------------------------------------------------------------+
double PriceHigh(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? 0 : prc[DATA_COUNT-index-1].high);
}
//+------------------------------------------------------------------+
//| >72@0I05B 87 <0AA820 F5=C Low ?> 8=45:AC B09<A5@88 (0 - 2) |
//+------------------------------------------------------------------+
double PriceLow(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? 0 : prc[DATA_COUNT-index-1].low);
}
//+------------------------------------------------------------------+
//| >72@0I05B 87 <0AA820 F5=C Close ?> 8=45:AC B09<A5@88 (0 - 2) |
//+------------------------------------------------------------------+
double PriceClose(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? 0 : prc[DATA_COUNT-index-1].close);
}
//+------------------------------------------------------------------+
//| >72@0I05B 87 <0AA820 2@5<O 10@0 ?> 8=45:AC B09<A5@88 (0 - 2) |
//+------------------------------------------------------------------+
datetime Time(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? 0 : prc[DATA_COUNT-index-1].time);
}
//+------------------------------------------------------------------+
//| >72@0I05B 87 <0AA820 40==K5 WPR ?> 8=45:AC B09<A5@88 (0 - 2) |
//+------------------------------------------------------------------+
double WPR(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? EMPTY_VALUE : wpr[DATA_COUNT-index-1]);
}
//+------------------------------------------------------------------+
//|>72@0I05B 87 <0AA820 40==K5 BB Upper ?> 8=45:AC B09<A5@88 (0 - 2)|
//+------------------------------------------------------------------+
double BBUpper(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? EMPTY_VALUE : bb0[DATA_COUNT-index-1]);
}
//+------------------------------------------------------------------+
//|>72@0I05B 87 <0AA820 40==K5 BB Lower ?> 8=45:AC B09<A5@88 (0 - 2)|
//+------------------------------------------------------------------+
double BBLower(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? EMPTY_VALUE : bb1[DATA_COUNT-index-1]);
}
//+-------------------------------------------------------------------+
//|>72@0I05B 87 <0AA820 40==K5 BB Middle ?> 8=45:AC B09<A5@88 (0 - 2)|
//+-------------------------------------------------------------------+
double BBMiddle(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? EMPTY_VALUE : bb2[DATA_COUNT-index-1]);
}
//+------------------------------------------------------------------+
//| >72@0I05B ?>;>28=C H8@8=K BB 2 ?C=:B0E |
//+------------------------------------------------------------------+
int HalfSizeBB(const int index)
{
double up=BBUpper(index);
double dn=BBLower(index);
if(up==EMPTY_VALUE || dn==EMPTY_VALUE)
return 0;
return (int)round(((up-dn)/2.0)/Point());
}
//+------------------------------------------------------------------+
//| >72@0I05B 87 <0AA820 40==K5 ATR ?> 8=45:AC B09<A5@88 (0 - 2) |
//+------------------------------------------------------------------+
double ATR(const int index)
{
return(index<0 || index>DATA_COUNT-1 ? EMPTY_VALUE : atr[DATA_COUNT-index-1]);
}
//+------------------------------------------------------------------+
//| !83=0; WPR |
//+------------------------------------------------------------------+
ENUM_SIGNAL_TYPE SignalWPR(void)
{
//--- >;CG05< F5=K WPR
double wpr0=WPR(1);
double wpr1=WPR(2);
//--- H81:0 - =5B A83=0;0
if(wpr0==EMPTY_VALUE || wpr1==EMPTY_VALUE)
return SIGNAL_TYPE_NONE;
//--- !83=0; =0 ?>:C?:C
if(wpr0>wpr1 && wpr1<=oversold_wpr)
return SIGNAL_TYPE_LONG;
//--- !83=0; =0 ?@>406C
if(wpr0<wpr1 && wpr1>=overbought_wpr)
return SIGNAL_TYPE_SHORT;
//--- 5B A83=0;0
return SIGNAL_TYPE_NONE;
}
//+------------------------------------------------------------------+
//| !83=0; BB |
//+------------------------------------------------------------------+
ENUM_SIGNAL_TYPE SignalBB(void)
{
//--- >;CG05< F5=K BB 8 Open
double bbup=BBUpper(0);
double bbdn=BBLower(0);
double bbmd=BBMiddle(0);
double price=PriceOpen(0);
//--- H81:0 - =5B A83=0;0
if(bbup==EMPTY_VALUE || bbdn==EMPTY_VALUE || bbmd==EMPTY_VALUE || price==0)
return SIGNAL_TYPE_NONE;
//--- !@54=85 F5=K 2KH5 8 =865 A@54=59 ;8=88
double upper=(bbup+bbmd)*0.5;
double lower=(bbdn+bbmd)*0.5;
//--- !83=0; 2 ;>=3
if(price<lower)
return SIGNAL_TYPE_LONG;
//--- !83=0; 2 H>@B
if(price>upper)
return SIGNAL_TYPE_SHORT;
//--- 5B A83=0;0
return SIGNAL_TYPE_NONE;
}
//+------------------------------------------------------------------+
//| !B028B A83=0;L=K5 7=0G:8 =0 3@0D8:5 |
//+------------------------------------------------------------------+
void SetArrow(const ENUM_INDICATOR indicator,const ENUM_SIGNAL_TYPE signal,bool chart_redraw)
{
//--- A;8 =5B A83=0;0, 8;8 ?5@540= =5 25@=K9 B8? 8=48:0B>@0 - CE>48<
if(signal==SIGNAL_TYPE_NONE || (indicator!=IND_WPR && indicator!=IND_BANDS))
return;
//--- >;CG05< 2@5<O >B:@KB8O B5:CI53> 10@0
datetime time=Time(0);
if(time==0)
return;
ENUM_OBJECT obj_type; // "8? >1J5:B0
double price=0; // &5=0 CAB0=>2:8 7=0G:0
//---  7028A8<>AB8 >B B8?0 8=48:0B>@0 CAB0=02;8205< F5=C 8 B8? 7=0G:0
switch(indicator)
{
//--- WPR
case IND_WPR :
price=PriceOpen(0);
obj_type=(signal==SIGNAL_TYPE_LONG ? OBJ_ARROW_BUY : OBJ_ARROW_SELL);
break;
//--- BB
default:
obj_type=OBJ_ARROW;
price=(signal==SIGNAL_TYPE_LONG ? BBLower(0) : BBUpper(0));
break;
}
//--- A;8 2@5<O ?>;CG8BL =5 C40;>AL - CE>48<
if(price==0)
return;
//--- !>740Q< 8<O >1J5:B0
string ind=(indicator==IND_WPR ? "_WPR" : "_BB");
string sig=(signal==SIGNAL_TYPE_LONG ? "_Long_signal_" : "_Short_signal_");
string name=program_name+ind+sig+TimeToString(time);
//--- A;8 >1J5:B A B0:8< 8<5=5< C65 5ABL - CE>48<
if(ObjectFind(0,name)==0)
return;
//--- !>740Q< >1J5:B
if(!ObjectCreate(0,name,obj_type,0,time,price))
return;
//--- CAB0=>28< F25B 7=0:0
ObjectSetInteger(0,name,OBJPROP_COLOR,(signal==SIGNAL_TYPE_LONG ? clrBlue : clrRed));
//--- CAB0=>28< AB8;L ;8=88 (?@8 2K45;5=88)
ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
//--- CAB0=>28< @07<5@ ;8=88 (?@8 2K45;5=88)
ObjectSetInteger(0,name,OBJPROP_WIDTH,0);
//--- CAB0=>28< :>4 AB@5;:8 4;O A83=0;0 BB
if(indicator==IND_BANDS)
ObjectSetInteger(0,name,OBJPROP_ARROWCODE,159);
//--- >B>1@078< =0 ?5@54=5< (false) 8;8 704=5< (true) ?;0=5
ObjectSetInteger(0,name,OBJPROP_BACK,false);
//--- >B:;NG8< @568< 2K45;5=8O 8 ?5@5<5I5=8O 7=0:0 <KHLN
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
ObjectSetInteger(0,name,OBJPROP_SELECTED,false);
//--- A:@>5< 8<O 3@0D8G5A:>3> >1J5:B0 2 A?8A:5 >1J5:B>2
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
//--- 5@5@8A>2K205< 3@0D8:
if(chart_redraw)
ChartRedraw();
}
//+------------------------------------------------------------------+
//| >72@0I05B B8? 8A?>;=5=8O >@45@0, @02=K9 type, |
//| 5A;8 >= 4>ABC?5= =0 A8<2>;5, 8=0G5 - :>@@5:B=K9 20@80=B |
//| https://www.mql5.com/ru/forum/170952/page4#comment_4128864 |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING GetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_RETURN)
{
const ENUM_SYMBOL_TRADE_EXECUTION exe_mode=(ENUM_SYMBOL_TRADE_EXECUTION)::SymbolInfoInteger(Symbol(),SYMBOL_TRADE_EXEMODE);
const int filling_mode=(int)::SymbolInfoInteger(Symbol(),SYMBOL_FILLING_MODE);
return((filling_mode==0 || (type>=ORDER_FILLING_RETURN) || ((filling_mode &(type+1))!=type+1)) ?
(((exe_mode==SYMBOL_TRADE_EXECUTION_EXCHANGE) || (exe_mode==SYMBOL_TRADE_EXECUTION_INSTANT)) ?
ORDER_FILLING_RETURN :((filling_mode==SYMBOL_FILLING_IOC) ? ORDER_FILLING_IOC : ORDER_FILLING_FOK)) : type);
}
//+------------------------------------------------------------------+
//| >72@0I05B :>@@5:B=K9 ;>B |
//+------------------------------------------------------------------+
double CorrectLots(const double lots,const bool to_min_correct=true)
{
double min=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
double max=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
double step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);
return(to_min_correct ? VolumeRoundToSmaller(lots,min,max,step) : VolumeRoundToCorrect(lots,min,max,step));
}
//+------------------------------------------------------------------+
//| >72@0I05B 1;8609H89 :>@@5:B=K9 ;>B |
//+------------------------------------------------------------------+
double VolumeRoundToCorrect(const double volume,const double min,const double max,const double step)
{
return(step==0 ? min : fmin(fmax(round(volume/step)*step,min),max));
}
//+------------------------------------------------------------------+
//| >72@0I05B 1;8609H89 2 <5=LHCN AB>@>=C :>@@5:B=K9 ;>B |
//+------------------------------------------------------------------+
double VolumeRoundToSmaller(const double volume,const double min,const double max,const double step)
{
return(step==0 ? min : fmin(fmax(floor(volume/step)*step,min),max));
}
//+------------------------------------------------------------------+
//| >72@0I05B D;03 =5 ?@52KH5=8O >1I53> >1JQ<0 =0 AGQB5 |
//+------------------------------------------------------------------+
bool CheckLotForLimitAccount(const ENUM_POSITION_TYPE position_type,const double volume)
{
double lots_limit=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT);
if(lots_limit==0)
return true;
double total_volume=(position_type==POSITION_TYPE_BUY ? Data.Buy.total_volume : Data.Sell.total_volume);
return(total_volume+volume<=lots_limit);
}
//+------------------------------------------------------------------+
//| >72@0I05B :>@@5:B=K9 StopLoss >B=>A8B5;L=> StopLevel |
//+------------------------------------------------------------------+
double CorrectStopLoss(const ENUM_POSITION_TYPE position_type,const int stop_loss)
{
if(stop_loss==0)
return 0;
double pt=Point();
double price=(position_type==POSITION_TYPE_BUY ? SymbolInfoDouble(Symbol(),SYMBOL_ASK) : SymbolInfoDouble(Symbol(),SYMBOL_BID));
int lv=StopLevel(), dg=Digits();
return(position_type==POSITION_TYPE_BUY ? NormalizeDouble(fmin(price-lv*pt,price-stop_loss*pt),dg) :
NormalizeDouble(fmax(price+lv*pt,price+stop_loss*pt),dg));
}
//+------------------------------------------------------------------+
//| >72@0I05B :>@@5:B=K9 TakeProfit >B=>A8B5;L=> StopLevel |
//+------------------------------------------------------------------+
double CorrectTakeProfit(const ENUM_POSITION_TYPE position_type,const int take_profit)
{
if(take_profit==0)
return 0;
double pt=Point();
double price=(position_type==POSITION_TYPE_BUY ? SymbolInfoDouble(Symbol(),SYMBOL_ASK) : SymbolInfoDouble(Symbol(),SYMBOL_BID));
int lv=StopLevel(), dg=Digits();
return(position_type==POSITION_TYPE_BUY ? NormalizeDouble(fmax(price+lv*pt,price+take_profit*pt),dg) :
NormalizeDouble(fmin(price-lv*pt,price-take_profit*pt),dg));
}
//+------------------------------------------------------------------+
//| >72@0I05B @0AAG8B0==K9 StopLevel |
//+------------------------------------------------------------------+
int StopLevel(void)
{
int sp=(int)SymbolInfoInteger(Symbol(),SYMBOL_SPREAD);
int lv=(int)SymbolInfoInteger(Symbol(),SYMBOL_TRADE_STOPS_LEVEL);
return(lv==0 ? sp*SPREAD_MLTP : lv);
}
//+------------------------------------------------------------------+
//| >72@0I05B "=5>?@545;Q==>5" A>AB>O=85 B>@3>2>3> >:@C65=8O |
//+------------------------------------------------------------------+
bool IsUncertainStateEnv(const string symbol_name,const ulong magic_number)
{
//---  B5AB5@5 A>A>B>O=85 >:@C65=8O 2A5340 :>@@5:B=>
if(MQLInfoInteger(MQL_TESTER))
return false;
//---  F8:;5 ?> :>;8G5AB2C >@45@>2
int total=OrdersTotal();
for(int i=total-1; i>=0; i--)
{
//--- 2K18@05< >@45@ 4;O ?>;CG5=8O 53> A2>9AB2
if(OrderGetTicket(i)==0)
continue;
//--- 5A;8 <038: >@45@0 =5 A>>B25BAB2C5B 8A:><><C - ?@>?CA:05<
if(OrderGetInteger(ORDER_MAGIC)!=magic_number)
continue;
//--- 5A;8 B8? >@45@0 =5 Buy 8 =5 Sell - ?@>?CA:05<
ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE);
if(type!=ORDER_TYPE_BUY && type!=ORDER_TYPE_SELL)
continue;
//--- 5A;8 A8<2>; >@45@0 A>>B25BAB2C5B 8A:><><C, => 2 >@45@5 =5B 70?8A8 >1 845=B8D8:0B>@5 ?>78F88,
//--- 7=0G8B 40==K5 >1 >B:@K20NI59AO ?>78F88 5IQ =5 4>102;5=K 2 8AB>@8N >@45@>2.
//--- -B> =5>?@545;Q==>5 A>AB>O=85 >:@C65=8O - 2>72@0I05< true
if(!OrderGetInteger(ORDER_POSITION_ID) && OrderGetString(ORDER_SYMBOL)==symbol_name)
return true;
}
//--- :@C65=85 2 ?>@O4:5
return false;
}
//+------------------------------------------------------------------+
//| @>25@:0 A>AB>O=8O >:@C65=8O |
//+------------------------------------------------------------------+
bool CheckUncertainStateEnv(const string symbol_name,const ulong magic_number,const int attempts,const int wait)
{
//--- A;8 >:@C65=85 2 ?>@O4:5 - 2>72@0I05< true
if(IsUncertainStateEnv(symbol_name,magic_number))
return true;
//--- 5;05< F8:;5 ENV_ATTEMPTS ?>?KB>: ?>;CG5=8O :>@@5:B=>3> >:@C65=8O A >6840=85< ENV_WAIT_ATTEMPT <564C ?>?KB:0<8
int n=0;
while(!IsStopped() && n<attempts && IsUncertainStateEnv(symbol_name,magic_number))
{
n++;
Sleep(wait);
}
//--- A;8 ?> 7025@H5=88 >6840=8O >:@C65=85 2AQ 5IQ =5>?@545;Q==>5 - A>>1I05< >1 MB>< 8 2>72@0I05< false
if(n>=attempts && IsUncertainStateEnv(symbol_name,magic_number))
{
PrintFormat("%s: Uncertain state of the environment. Please try again.",__FUNCTION__);
return false;
}
//--- :@C65=85 :>@@5:B=>
return true;
}
//+------------------------------------------------------------------+
//| 0?>;=O5B <0AA82K B8:5B>2 ?>78F89 |
//+------------------------------------------------------------------+
bool FillingListTickets(const string symbol_name,const ulong magic_number)
{
//--- A;8 B>@3>2>5 >:@C65=85 =5 :>@@5:B=> - 2>72@0I05< false
if(!CheckUncertainStateEnv(symbol_name,magic_number,ENV_ATTEMPTS,ENV_WAIT_ATTEMPT))
return false;
//--- G8I05< A?8A:8 8 8=8F80;878@C5< ?5@5<5==K5
Data.Buy.list_tickets.Clear();
Data.Sell.list_tickets.Clear();
Data.Buy.total_volume=0;
Data.Sell.total_volume=0;
//---  F8:;5 ?> >B:@KBK< ?>78F8O<
int total=PositionsTotal();
for(int i=total-1; i>WRONG_VALUE; i--)
{
//--- 2K18@05< ?>78F8N 4;O ?>;CG5=8O A2>9AB2
ulong ticket=PositionGetTicket(i);
if(ticket==0)
continue;
//--- A;8 <038: 8;8 A8<2>; =5 A>>B25BAB2CNB ?5@540==K< 2 DC=:F8N - 84Q< 40;LH5
if(PositionGetInteger(POSITION_MAGIC)!=InpMagic || PositionGetString(POSITION_SYMBOL)!=symbol_name)
continue;
//--- >;CG05< B8? 8 >1JQ< ?>78F88
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double volume=PositionGetDouble(POSITION_VOLUME);
//---  7028A8<>AB8 >B B8?0 ?>78F88 4>102;O5< B8:5B 8 >1JQ< 2 A>>B25BAB2CNI85 A?8A:8
if(type==POSITION_TYPE_BUY)
{
Data.Buy.list_tickets.Add(ticket);
Data.Buy.total_volume+=volume;
}
//--- POSITION_TYPE_SELL
else
{
Data.Sell.list_tickets.Add(ticket);
Data.Sell.total_volume+=volume;
}
}
//--- AQ CA?5H=>
return true;
}
//+------------------------------------------------------------------+
//| >72@0I05B :>;8G5AB2> ?>78F89 Buy |
//+------------------------------------------------------------------+
int TotalBuy(void)
{
return Data.Buy.list_tickets.Total();
}
//+------------------------------------------------------------------+
//| >72@0I05B :>;8G5AB2> ?>78F89 Sell |
//+------------------------------------------------------------------+
int TotalSell(void)
{
return Data.Sell.list_tickets.Total();
}
//+------------------------------------------------------------------+
//| >72@0I05B ?>A;54=89 4>102;5==K9 B8:5B ?>78F88 ?> B8?C |
//+------------------------------------------------------------------+
ulong LastAddedTicket(const ENUM_POSITION_TYPE type)
{
return(type==POSITION_TYPE_BUY ? (TotalBuy()>0 ? Data.Buy.list_tickets.At(0) : 0) : (TotalSell()>0 ? Data.Sell.list_tickets.At(0) : 0));
}
//+------------------------------------------------------------------+
//| >72@0I05B =><5@ 10@0, =0 :>B>@>< 1K;0 >B:@KB0 ?>78F8O |
//+------------------------------------------------------------------+
int PositionBar(const ulong ticket)
{
//--- K18@05< ?>78F8N ?> B8:5BC
ResetLastError();
if(!PositionSelectByTicket(ticket))
{
PrintFormat("%s: Failed to select position by ticket #%I64u. Error %d",__FUNCTION__,ticket,GetLastError());
return -1;
}
//--- >;CG05< 2@5<O >B:@KB8O 8 A8<2>; ?>78F88
datetime time=(datetime)PositionGetInteger(POSITION_TIME);
string symbol=PositionGetString(POSITION_SYMBOL);
//--- >72@0I05< =><5@ 10@0 ?> 2@5<5=8 >B:@KB8O ?>78F88
return iBarShift(symbol,PERIOD_CURRENT,time);
}
//+------------------------------------------------------------------+
//| >72@0I05B =0;8G85 C:070==>9 ?>78F88, >B:@KB>9 =0 B5:CI5< 10@5 |
//+------------------------------------------------------------------+
bool IsPresentPosOnCurrentBar(const ENUM_POSITION_TYPE type)
{
ulong ticket=LastAddedTicket(type);
return(ticket>0 ? PositionBar(ticket)==0 : false);
}
//+------------------------------------------------------------------+
//| >72@0I05B F5=C >B:@KB8O ?>78F88 ?> B8:5BC |
//+------------------------------------------------------------------+
double PositionPriceOpen(const ulong ticket)
{
//--- @>25@O5< B8:5B
if(ticket==0)
return 0;
//--- K18@05< ?>78F8N ?> B8:5BC
ResetLastError();
if(!PositionSelectByTicket(ticket))
{
PrintFormat("%s: Failed to select position by ticket #%I64u. Error %d",__FUNCTION__,ticket,GetLastError());
return 0;
}
//--- >72@0I05< F5=C >B:@KB8O ?>78F88
return PositionGetDouble(POSITION_PRICE_OPEN);
}
//+------------------------------------------------------------------+
//| 0:@K205B ?>78F88 Buy |
//+------------------------------------------------------------------+
bool CloseBuy(void)
{
int total=TotalBuy();
bool res=true;
for(int i=total-1; i>=0; i--)
{
ulong ticket=Data.Buy.list_tickets.At(i);
if(ticket==NULL)
continue;
if(!trade.PositionClose(ticket,InpDeviation))
res=false;
}
return res;
}
//+------------------------------------------------------------------+
//| 0:@K205B ?>78F88 Sell |
//+------------------------------------------------------------------+
bool CloseSell(void)
{
int total=TotalSell();
bool res=true;
for(int i=total-1; i>=0; i--)
{
ulong ticket=Data.Sell.list_tickets.At(i);
if(ticket==NULL)
continue;
if(!trade.PositionClose(ticket,InpDeviation))
res=false;
}
return res;
}
//+------------------------------------------------------------------+
//| B:@KB85 ?>78F88 |
//+------------------------------------------------------------------+
bool OpenPosition(const string symbol_name,const ENUM_POSITION_TYPE type,const double volume,const string comment)
{
//--- 0AAG8BK205< 7=0G5=8O 4;O AB>?-?@8:07>2
int bb=int(HalfSizeBB(0)*InpSLMltp);
double atrd=ATR(0);
int atrp=(atrd!=EMPTY_VALUE ? int(round(atrd*InpTPMltp/Point())) : 0);
double sl=(InpStopLoss==0 ? 0 : (InpStopLoss<0 ? (bb!=0 ? CorrectStopLoss(type,bb) : 0) : CorrectStopLoss(type,InpStopLoss)));
double tp=(InpTakeProfit==0 ? 0 : (InpStopLoss<0 ? (atrp!=0 ? CorrectTakeProfit(type,atrp) : 0) : CorrectTakeProfit(type,InpTakeProfit)));
//--- 0 =5BB8=3>2>< AGQB5 C18@05< AB>?-?@8:07K
if(netto)
sl=tp=0;
//--- >;CG05< F5=K
MqlTick tick={};
if(!SymbolInfoTick(symbol_name,tick))
{
PrintFormat("%s: Unable to get prices");
return false;
}
//--- @>25@O5< 8 ?>;CG05< =>@<0;87>20==K9 ;>B >B:@K205<>9 ?>78F88
double ll=trade.CheckVolume(symbol_name,volume,(type==POSITION_TYPE_BUY ? tick.ask : tick.bid),(ENUM_ORDER_TYPE)type);
if(ll==0)
{
PrintFormat("%s: Error. CheckVolume() returned a zero lot",__FUNCTION__);
return false;
}
//--- @>25@O5< >3@0=8G5=85 =0 <0:A8<0;L=K9 >1JQ< >B:@KBKE ?>78F89 =0 AGQB5
if(!CheckLotForLimitAccount(type,ll))
{
PrintFormat("%s: CheckLotForLimitAccount() returned an error",__FUNCTION__);
return false;
}
//--- >65B 1KBL A8BC0F8O, :>340 B>@3>2K9 ?@8:07 C65 1K; >B?@02;5=, => >= 5IQ =5 ?>;=>ABLN >1@01>B0=,
//--- GB> <>65B ?@825AB8 : 7042>5=8N >B:@K205<>9 ?>78F88.
//--- A;8 B>@3>2>5 >:@C65=85 =5 :>@@5:B=> - 2>72@0I05< false
if(!CheckUncertainStateEnv(symbol_name,InpMagic,ENV_ATTEMPTS,ENV_WAIT_ATTEMPT))
return false;
//--- 6840=85 ?>;CG5=8O :>@@5:B=>3> B>@3>2>3> >:@C65=8O <>65B 70=OBL =5:>B>@>5 2@5<O
//--- IQ @07 ?>;CG8< F5=K
if(!SymbolInfoTick(symbol_name,tick))
{
PrintFormat("%s: Unable to get prices");
return false;
}
//--- >72@0I05< @57C;LB0B >B?@02:8 B>@3>2>3> 70?@>A0 =0 A5@25@
return(type==POSITION_TYPE_BUY ? trade.Buy(ll,symbol_name,tick.ask,sl,tp,comment) : trade.Sell(ll,symbol_name,tick.bid,sl,tp,comment));
}
//+------------------------------------------------------------------+
//| @>F5AA B>@3>2;8 |
//+------------------------------------------------------------------+
void TradeProcess(const ENUM_SIGNAL_TYPE signal)
{
//--- 5B A83=0;0 - CE>48<
if(signal==SIGNAL_TYPE_NONE)
return;
//--- !83=0; =0 ?>:C?:C
if(signal==SIGNAL_TYPE_LONG)
{
//--- A;8 =5B >B:@KB>9 ?>78F88 Buy =0 MB>< 10@5
if(!IsPresentPosOnCurrentBar(POSITION_TYPE_BUY))
{
//--- >;CG05< F5=C ?>A;54=59 >B:@KB>9 ?>78F88 Buy
double price_last=PositionPriceOpen(LastAddedTicket(POSITION_TYPE_BUY));
//--- A;8 MB> A0<0O ?5@20O ?>78F8O Buy, ;81> F5=0 >B:@KB8O ;CGH5 F5=K >B:@KB8O ?@>H;>9 ?>78F88 -
//--- >BAK;05< 70?@>A =0 >B:@KB85 ?>78F88 Buy
if(price_last==0 || price_last>SymbolInfoDouble(Symbol(),SYMBOL_ASK))
{
//--- A;8 ?>78F8O >B:@KB0 - >1=>2;O5< A?8A:8 B8:5B>2 >B:@KBKE ?>78F89
if(OpenPosition(Symbol(),POSITION_TYPE_BUY,lot,""))
FillingListTickets(Symbol(),InpMagic);
}
}
}
//--- !83=0; =0 ?@>406C
if(signal==SIGNAL_TYPE_SHORT)
{
//--- A;8 =5B >B:@KB>9 ?>78F88 Sell =0 MB>< 10@5
if(!IsPresentPosOnCurrentBar(POSITION_TYPE_SELL))
{
//--- >;CG05< F5=C ?>A;54=59 >B:@KB>9 ?>78F88 Sell
double price_last=PositionPriceOpen(LastAddedTicket(POSITION_TYPE_SELL));
//--- A;8 MB> A0<0O ?5@20O ?>78F8O Sell, ;81> F5=0 >B:@KB8O ;CGH5 F5=K >B:@KB8O ?@>H;>9 ?>78F88 -
//--- >BAK;05< 70?@>A =0 >B:@KB85 ?>78F88 Sell
if(price_last<SymbolInfoDouble(Symbol(),SYMBOL_ASK))
{
//--- A;8 ?>78F8O >B:@KB0 - >1=>2;O5< A?8A:8 B8:5B>2 >B:@KBKE ?>78F89
if(OpenPosition(Symbol(),POSITION_TYPE_SELL,lot,""))
FillingListTickets(Symbol(),InpMagic);
}
}
}
}
//+------------------------------------------------------------------+