//+------------------------------------------------------------------+ //| eEquityTrailing.mq4 | //| * | //| * | //+------------------------------------------------------------------+ #property copyright "*" #property link "*" /* Трейлинг эквити. По принципу работе аналогичен работе трейлинга ордера. При достижении заданного значения эквити эксперт начинает фиксировать максимальное значение эквити, затем, в случае снижения эквити на заданную величину выполняется закрытие всех ордеров открытых на счете. Все настройки (за исключением выбора цветовой схемы) выполняются через управление свойством "Текст" графических объектов. Графические объекты находятся в правом верхнем углу графика. Элементы управления: 1. ON/OF - включение/выключение эксперта. Эксперт может постоянно быть на графике и использоваться по мере необходимости. 2. StartEquity ($) - Эквити при достижении которого начинается перемещение уровня закрытия. 3. Level ($) - Уровень закрытия. При изменении значений можно использовать запятую в качестве десятичного разделителя, не только точку. Информационные надписи: 4. MaxEquity ($) - максимальное эквити, зафиксированное от момента включения эксперта. При необходимости значение можно менять также как у надписей - элементов управления. 5. CloseEquity ($) - уровень эквити, при снижении до которого будет выполнено закрытие. 6. Equity ($) - текущее эквити. Знак ($) - единица измерения - валюта депозита (не обязательно доллары). Эксперт не боится перезапуска терминала или компьютера, переключения графика: таймфрейма, символа. Все данные сохраняются в надписях. Надписи удаляются только при снятии эксперта с графика или при переключении счета. Перед началом выполнения закрытия открывается алерт с сообщением "Выполняю закрытие". После выполнения закрытия эксперт отключается (через надпись ON/OF). Внешние параметры: BlackBG - Цветовая схема для черного фона, false - для белого. */ extern bool BlackBG=true; // Цветовая схема для черного фона, false - для белого. color Caption; // Цвет надписей color Control; // Цвет элементов управления (надписей в которых можно менять значения) color ControlInfo; // Цвет информационной надписи, в которой можно менять значение. color On; // Цвет выключателя во включенном состоянии. color Of; // Цвет выключателя в выключенном состоянии. double StartEquity$=0; double Level$=100.0; double MaxEq; bool CloseFlag; bool OnOf=false; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init(){ Caption=White; Control=Yellow; ControlInfo=Red; On=Lime; Of=Silver; if(!BlackBG){ Caption = Black; Control = Chocolate; ControlInfo = Red; On = Green; Of = Gray; } OnOf=false; if(ObjectFind(WindowExpertName()+"_OnOf")==0){ if(ObjectDescription(WindowExpertName()+"_OnOf")=="ON"){ OnOf=true; } } return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- if(UninitializeReason()==REASON_REMOVE || UninitializeReason()==REASON_ACCOUNT){ fObjDeleteByPrefix(WindowExpertName()); } //---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start(){ //if(OrdersTotal()==0) //OrderSend(Symbol(),OP_BUY,0.1,NormalizeDouble(Ask,Digits),0,NormalizeDouble(Ask-Point*200,Digits),NormalizeDouble(Ask+Point*350,Digits),NULL,0,0,CLR_NONE); fGUI_OnOff_Simple(WindowExpertName()+"_OnOf",OnOf,"ON","OF",5,15,1,On,Of,"Arial",8); fObjLabel(WindowExpertName()+"_StEq_Lbl",5,30,"StartEquity ($)",1,Caption,8,0,"Arial",false); if(ObjectFind(WindowExpertName()+"_StEq_Value")!=0){ fObjLabel(WindowExpertName()+"_StEq_Value",85,30,DS2(StartEquity$),1,Control,8,0,"Arial",false); } ObjectSet(WindowExpertName()+"_StEq_Value",OBJPROP_XDISTANCE,85); ObjectSet(WindowExpertName()+"_StEq_Value",OBJPROP_YDISTANCE,30); ObjectSet(WindowExpertName()+"_StEq_Value",OBJPROP_COLOR,Control); string tmp=ObjectDescription(WindowExpertName()+"_StEq_Value"); fStrReplace(tmp,",","."); StartEquity$=StrToDouble(tmp); ObjectSetText(WindowExpertName()+"_StEq_Value",DS2(StartEquity$)); fObjLabel(WindowExpertName()+"_Level_Lbl",5,45,"Level ($)",1,Caption,8,0,"Arial",false); if(ObjectFind(WindowExpertName()+"_Level_Value")!=0){ fObjLabel(WindowExpertName()+"_Level_Value",85,45,DS2(Level$),1,Control,8,0,"Arial",false); } ObjectSet(WindowExpertName()+"_Level_Value",OBJPROP_XDISTANCE,85); ObjectSet(WindowExpertName()+"_Level_Value",OBJPROP_YDISTANCE,45); ObjectSet(WindowExpertName()+"_Level_Value",OBJPROP_COLOR,Control); tmp=ObjectDescription(WindowExpertName()+"_Level_Value"); fStrReplace(tmp,",","."); Level$=StrToDouble(tmp); ObjectSetText(WindowExpertName()+"_Level_Value",DS2(Level$)); fObjLabel(WindowExpertName()+"_MaxEquity_Lbl",5,60,"MaxEquity ($)",1,Caption,8,0,"Arial",false); if(ObjectFind(WindowExpertName()+"_MaxEquity")!=0){ fObjLabel(WindowExpertName()+"_MaxEquity",85,60,DS2(MaxEq),1,ControlInfo,8,0,"Arial",false); } else{ tmp=ObjectDescription(WindowExpertName()+"_MaxEquity"); fStrReplace(tmp,",","."); MaxEq=StrToDouble(tmp); } ObjectSet(WindowExpertName()+"_MaxEquity",OBJPROP_XDISTANCE,85); ObjectSet(WindowExpertName()+"_MaxEquity",OBJPROP_YDISTANCE,60); ObjectSet(WindowExpertName()+"_MaxEquity",OBJPROP_COLOR,ControlInfo); if(MaxEq!=0 && OnOf){ fObjLabel(WindowExpertName()+"_CloseLevel_Lbl_1",5,75,"CloseEquity ($)",1,Caption,8,0,"Arial",false); fObjLabel(WindowExpertName()+"_CloseLevel_Lbl_2",85,75,DS2(MaxEq-Level$),1,Caption,8,0,"Arial",false); } else{ fObjLabel(WindowExpertName()+"_CloseLevel_Lbl_1",5,75,"CloseEquity ($)",1,Caption,8,0,"Arial",false); fObjLabel(WindowExpertName()+"_CloseLevel_Lbl_2",85,75,"NO",1,Caption,8,0,"Arial",false); } fObjLabel(WindowExpertName()+"_Equity_Lbl_1",5,90,"Equity ($)",1,Caption,8,0,"Arial",false); fObjLabel(WindowExpertName()+"_Equity_Lbl_2",85,90,DS2(AccountEquity()),1,Caption,8,0,"Arial",false); WindowRedraw(); if(OnOf){ if(AccountEquity()>=StartEquity$){ MaxEq=MathMax(MaxEq,AccountEquity()); ObjectSetText(WindowExpertName()+"_MaxEquity",DS2(MaxEq)); } if(MaxEq!=0){ if(ND2(AccountEquity()-(MaxEq-Level$))<=0){ CloseFlag=true; } } } if(CloseFlag){ if(fCloseAllTotal()==0){ CloseFlag=false; Alert(WindowExpertName()+": Выполняю закрытие"); fInit(); } else{ return(0); } } return(0); } //+------------------------------------------------------------------+ double ND2(double v){return(NormalizeDouble(v,2));} void fInit(){ MaxEq=0; ObjectSetText(WindowExpertName()+"_MaxEquity",DS2(MaxEq)); StartEquity$=0; OnOf=false; fGUI_OnOff_Simple(WindowExpertName()+"_OnOf",OnOf,"ON","OF",5,15,1,On,Of,"Arial",8); fObjLabel(WindowExpertName()+"_CloseLevel_Lbl_2",85,75,"NO",1,Caption,8,0,"Arial",false); WindowRedraw(); } void fObjDeleteByPrefix(string aPrefix){ for(int i=ObjectsTotal()-1;i>=0;i--){ if(StringFind(ObjectName(i),aPrefix,0)==0){ ObjectDelete(ObjectName(i)); } } } void fGUI_OnOff_Simple(string aObjName, bool & aState,string aCaptionON, string aCaptionOFF,int aX=5, int aY=5,int aCorner=0, color aColorON=Lime, color aColorOFF=Silver, string aFont="Arial", int aFontSize=8){ if(ObjectFind(aObjName)!=0){ string tmpCaption=aCaptionOFF; color tmpColor=aColorOFF; if(aState){ tmpCaption=aCaptionON; tmpColor=aColorON; } fObjLabel(aObjName,aX,aY,tmpCaption,aCorner,tmpColor,aFontSize,0,aFont,false); } if(ObjectFind(aObjName)==0){ int xp=ObjectGet(aObjName,OBJPROP_XDISTANCE); int yp=ObjectGet(aObjName,OBJPROP_YDISTANCE); string txt=ObjectDescription(aObjName); tmpColor=ObjectGet(aObjName,OBJPROP_COLOR); if(xp!=aX || yp!=aY){ ObjectDelete(aObjName); fObjLabel(aObjName,aX,aY,aCaptionON,aCorner,tmpColor,aFontSize,0,aFont,false); xp=ObjectGet(aObjName,OBJPROP_XDISTANCE); yp=ObjectGet(aObjName,OBJPROP_YDISTANCE); if(xp==aX && yp==aY){ if(aCaptionON!=aCaptionOFF){ if(txt==aCaptionOFF){ aState=true; } else{ aState=false; } } else{ if(tmpColor==aColorOFF){ aState=true; } else{ aState=false; } } if(aState){ txt=aCaptionON; tmpColor=aColorON; } else{ txt=aCaptionOFF; tmpColor=aColorOFF; } fObjLabel(aObjName,aX,aY,txt,aCorner,tmpColor,aFontSize,0,aFont,false); } } else{ tmpCaption=aCaptionOFF; tmpColor=aColorOFF; if(aState){ tmpCaption=aCaptionON; tmpColor=aColorON; } fObjLabel(aObjName,aX,aY,tmpCaption,aCorner,tmpColor,aFontSize,0,aFont,false); } } } int fCloseAllTotal(){ int tErr=0; for(int i=OrdersTotal()-1;i>=0;i--){ if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){ if(OrderType()==OP_BUY){ RefreshRates(); if(!IsTradeContextBusy()){ if(!OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),MarketInfo(OrderSymbol(),MODE_SPREAD)*3,CLR_NONE)){ int tCheck=GetLastError(); Print("Error close BUY "+OrderTicket()+" "+fMyErDesc(tCheck)); tErr=-1; } } else{ static int lt1=0; if(TimeCurrent()>lt1+20){ lt1=TimeCurrent(); Print("Need close BUY "+OrderTicket()+". Trade Context Busy"); } return(-2); } } if(OrderType()==OP_SELL){ RefreshRates(); if(!IsTradeContextBusy()){ if(!OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),MarketInfo(OrderSymbol(),MODE_SPREAD)*3,CLR_NONE)){ tCheck=GetLastError(); Print("Error close SELL "+OrderTicket()+" "+fMyErDesc(tCheck)); tErr=-1; } } else{ static int lt2=0; if(TimeCurrent()>lt2+20){ lt2=TimeCurrent(); Print("Need close SELL "+OrderTicket()+". Trade Context Busy"); } return(-2); } } } else{ tErr=-3; } } return(tErr); } void fObjLabel( string aObjectName, // 1 имя int aX, // 2 х int aY, // 3 у string aText, // 4 текст int aCorner=0, // 5 угол 0 1 // 2 3 color aColor=Red, // 6 цвет int aFontSize=8, // 7 размер шрифта int aWindowNumber=0, // 8 окно string aFont="Arial", // 9 шрифт bool aBack=false // 10 фон ){ if(ObjectFind(aObjectName)!=aWindowNumber){ ObjectCreate(aObjectName,OBJ_LABEL,aWindowNumber,0,0); } ObjectSet(aObjectName,OBJPROP_XDISTANCE,aX); ObjectSet(aObjectName,OBJPROP_YDISTANCE,aY); ObjectSetText(aObjectName,aText,aFontSize,aFont,aColor); ObjectSet(aObjectName,OBJPROP_BACK,aBack); ObjectSet(aObjectName,OBJPROP_CORNER,aCorner); } string fStrReplace(string aString, string aFind, string aReplace){ int tPos1=0; string RetStr=""; int tFindLength=StringLen(aFind); int tPos2=StringFind(aString,aFind,tPos1); while(tPos2!=-1){ if(tPos2>tPos1){ RetStr=RetStr+StringSubstr(aString,tPos1,tPos2-tPos1); } RetStr=RetStr+aReplace; tPos1=tPos2+tFindLength; tPos2=StringFind(aString,aFind,tPos1); } RetStr=RetStr+StringSubstr(aString,tPos1,StringLen(aString)-tPos1); return(RetStr); } string DS2(double v){return(DoubleToStr(v,2));} string fMyErDesc(int aErrNum){ // fMyErDesc(GetLastError()); string pref="Err Num: "+aErrNum+" - "; switch(aErrNum){ case 0: return(pref+"NO ERROR"); case 1: return(pref+"NO RESULT"); case 2: return(pref+"COMMON ERROR"); case 3: return(pref+"INVALID TRADE PARAMETERS"); case 4: return(pref+"SERVER BUSY"); case 5: return(pref+"OLD VERSION"); case 6: return(pref+"NO CONNECTION"); case 7: return(pref+"NOT ENOUGH RIGHTS"); case 8: return(pref+"TOO FREQUENT REQUESTS"); case 9: return(pref+"MALFUNCTIONAL TRADE"); case 64: return(pref+"ACCOUNT DISABLED"); case 65: return(pref+"INVALID ACCOUNT"); case 128: return(pref+"TRADE TIMEOUT"); case 129: return(pref+"INVALID PRICE"); case 130: return(pref+"INVALID STOPS"); case 131: return(pref+"INVALID TRADE VOLUME"); case 132: return(pref+"MARKET CLOSED"); case 133: return(pref+"TRADE DISABLED"); case 134: return(pref+"NOT ENOUGH MONEY"); case 135: return(pref+"PRICE CHANGED"); case 136: return(pref+"OFF QUOTES"); case 137: return(pref+"BROKER BUSY"); case 138: return(pref+"REQUOTE"); case 139: return(pref+"ORDER LOCKED"); case 140: return(pref+"LONG POSITIONS ONLY ALLOWED"); case 141: return(pref+"TOO MANY REQUESTS"); case 145: return(pref+"TRADE MODIFY DENIED"); case 146: return(pref+"TRADE CONTEXT BUSY"); case 147: return(pref+"TRADE EXPIRATION DENIED"); case 148: return(pref+"TRADE TOO MANY ORDERS"); //---- mql4 run time errors case 4000: return(pref+"NO MQLERROR"); case 4001: return(pref+"WRONG FUNCTION POINTER"); case 4002: return(pref+"ARRAY INDEX OUT OF RANGE"); case 4003: return(pref+"NO MEMORY FOR FUNCTION CALL STACK"); case 4004: return(pref+"RECURSIVE STACK OVERFLOW"); case 4005: return(pref+"NOT ENOUGH STACK FOR PARAMETER"); case 4006: return(pref+"NO MEMORY FOR PARAMETER STRING"); case 4007: return(pref+"NO MEMORY FOR TEMP STRING"); case 4008: return(pref+"NOT INITIALIZED STRING"); case 4009: return(pref+"NOT INITIALIZED ARRAYSTRING"); case 4010: return(pref+"NO MEMORY FOR ARRAYSTRING"); case 4011: return(pref+"TOO LONG STRING"); case 4012: return(pref+"REMAINDER FROM ZERO DIVIDE"); case 4013: return(pref+"ZERO DIVIDE"); case 4014: return(pref+"UNKNOWN COMMAND"); case 4015: return(pref+"WRONG JUMP"); case 4016: return(pref+"NOT INITIALIZED ARRAY"); case 4017: return(pref+"DLL CALLS NOT ALLOWED"); case 4018: return(pref+"CANNOT LOAD LIBRARY"); case 4019: return(pref+"CANNOT CALL FUNCTION"); case 4020: return(pref+"EXTERNAL EXPERT CALLS NOT ALLOWED"); case 4021: return(pref+"NOT ENOUGH MEMORY FOR RETURNED STRING"); case 4022: return(pref+"SYSTEM BUSY"); case 4050: return(pref+"INVALID FUNCTION PARAMETERS COUNT"); case 4051: return(pref+"INVALID FUNCTION PARAMETER VALUE"); case 4052: return(pref+"STRING FUNCTION INTERNAL ERROR"); case 4053: return(pref+"SOME ARRAY ERROR"); case 4054: return(pref+"INCORRECT SERIES ARRAY USING"); case 4055: return(pref+"CUSTOM INDICATOR ERROR"); case 4056: return(pref+"INCOMPATIBLE ARRAYS"); case 4057: return(pref+"GLOBAL VARIABLES PROCESSING ERROR"); case 4058: return(pref+"GLOBAL VARIABLE NOT FOUND"); case 4059: return(pref+"FUNCTION NOT ALLOWED IN TESTING MODE"); case 4060: return(pref+"FUNCTION NOT CONFIRMED"); case 4061: return(pref+"SEND MAIL ERROR"); case 4062: return(pref+"STRING PARAMETER EXPECTED"); case 4063: return(pref+"INTEGER PARAMETER EXPECTED"); case 4064: return(pref+"DOUBLE PARAMETER EXPECTED"); case 4065: return(pref+"ARRAY AS PARAMETER EXPECTED"); case 4066: return(pref+"HISTORY WILL UPDATED"); case 4067: return(pref+"TRADE ERROR"); case 4099: return(pref+"END OF FILE"); case 4100: return(pref+"SOME FILE ERROR"); case 4101: return(pref+"WRONG FILE NAME"); case 4102: return(pref+"TOO MANY OPENED FILES"); case 4103: return(pref+"CANNOT OPEN FILE"); case 4104: return(pref+"INCOMPATIBLE ACCESS TO FILE"); case 4105: return(pref+"NO ORDER SELECTED"); case 4106: return(pref+"UNKNOWN SYMBOL"); case 4107: return(pref+"INVALID PRICE PARAM"); case 4108: return(pref+"INVALID TICKET"); case 4109: return(pref+"TRADE NOT ALLOWED"); case 4110: return(pref+"LONGS NOT ALLOWED"); case 4111: return(pref+"SHORTS NOT ALLOWED"); case 4200: return(pref+"OBJECT ALREADY EXISTS"); case 4201: return(pref+"UNKNOWN OBJECT PROPERTY"); case 4202: return(pref+"OBJECT DOES NOT EXIST"); case 4203: return(pref+"UNKNOWN OBJECT TYPE"); case 4204: return(pref+"NO OBJECT NAME"); case 4205: return(pref+"OBJECT COORDINATES ERROR"); case 4206: return(pref+"NO SPECIFIED SUBWINDOW"); case 4207: return(pref+"SOME OBJECT ERROR"); default: return(pref+"WRONG ERR NUM"); } }