diff --git a/Experts/Nkanven/CandleCount.mq5 b/Experts/Nkanven/CandleCount.mq5 new file mode 100644 index 0000000..4dcaa4d --- /dev/null +++ b/Experts/Nkanven/CandleCount.mq5 @@ -0,0 +1,72 @@ +//+------------------------------------------------------------------+ +//| CandleCount.mq5 | +//| Copyright 2022, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include //EA paramters +#include //Trading hours checks +#include //Trading conditions checks +#include //Trading conditions checks +#include //Lot size calculator +#include //Lot size calculator +#include //Emergency close of transaction +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +#include +CiATR* atr; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + atr = new CiATR(); + atr.Create(gSymbol, InpTimeFrame, InpAtrPeriod); +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + TimeCurrent(dt); + + SymbolInfoTick(_Symbol,last_tick); + + CheckOperationHours(); + CheckPreChecks(); + ScanPositions(); + + //Get ATR values + atr.Refresh(-1); + gAtr = atr.Main(1); + + if(!gIsPreChecksOk) + return; + + if(InpActivateRiskWatcher) + { + drawdownWatcher(); + CloseTransactions(); + } + ExecuteEntry(); + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/CandleCount/CheckHistory.mqh b/Include/Nkanven/CandleCount/CheckHistory.mqh new file mode 100644 index 0000000..8c5f1b0 --- /dev/null +++ b/Include/Nkanven/CandleCount/CheckHistory.mqh @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| CheckHistory.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" +//+------------------------------------------------------------------+ +//| defines | +//+------------------------------------------------------------------+ +// #define MacrosHello "Hello, world!" +// #define MacrosYear 2010 +//+------------------------------------------------------------------+ +//| DLL imports | +//+------------------------------------------------------------------+ +// #import "user32.dll" +// int SendMessageA(int hWnd,int Msg,int wParam,int lParam); +// #import "my_expert.dll" +// int ExpertRecalculate(int wParam,int lParam); +// #import +//+------------------------------------------------------------------+ +//| EX5 imports | +//+------------------------------------------------------------------+ +// #import "stdlib.ex5" +// string ErrorDescription(int error_code); +// #import +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/CandleCount/CloseTransactions.mqh b/Include/Nkanven/CandleCount/CloseTransactions.mqh new file mode 100644 index 0000000..ab1575d --- /dev/null +++ b/Include/Nkanven/CandleCount/CloseTransactions.mqh @@ -0,0 +1,74 @@ +//+------------------------------------------------------------------+ +//| CloseTransactions.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +CTrade trade; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void CloseTransactions() + { + bool result = true; + int cts = PositionsTotal(); + ulong theTicket; + double positionProfit = 0.0; + + if(cts > 0) + { + for(int i = cts-1; i>=0; i--) + { + ulong ticket = PositionGetTicket(i); + if(PositionSelectByTicket(ticket)) + { + if(PositionGetInteger(POSITION_MAGIC)==InpMagicNumber) + { + if(positionProfit > PositionGetDouble(POSITION_PROFIT)) + { + positionProfit = PositionGetDouble(POSITION_PROFIT); + theTicket = ticket; + } + } + } + else + { + Print("Error (", GetLastError(), ") while selecting position by ticket"); + } + } + if(gEmergencyClose) + { + if(!trade.PositionClose(theTicket)) + Print("Error (", GetLastError(), ") while deleting all buy positions"); + } + } + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void drawdownWatcher() + { + double amountDiff, equity, balance, percentDiff; + balance=AccountInfoDouble(ACCOUNT_BALANCE); + equity=AccountInfoDouble(ACCOUNT_EQUITY); + gEmergencyClose = false; + + if(equity < balance) + { + amountDiff = balance - equity; + percentDiff = (amountDiff*100)/balance; + + Print("amountDiff ", amountDiff, " percentDiff ", percentDiff, " InpMaxDrawdown ", InpMaxDrawdown); + + if(InpMaxDrawdown < percentDiff) + { + gEmergencyClose = true; + } + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/CandleCount/EntriesManager.mqh b/Include/Nkanven/CandleCount/EntriesManager.mqh new file mode 100644 index 0000000..0651068 Binary files /dev/null and b/Include/Nkanven/CandleCount/EntriesManager.mqh differ diff --git a/Include/Nkanven/CandleCount/LotSizeCal.mqh b/Include/Nkanven/CandleCount/LotSizeCal.mqh new file mode 100644 index 0000000..7bf44fc --- /dev/null +++ b/Include/Nkanven/CandleCount/LotSizeCal.mqh @@ -0,0 +1,62 @@ +//+------------------------------------------------------------------+ +//| LotSizeCal.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + + +//Lot Size Calculator +void LotSizeCalculate(double SL=0) + { +//If the position size is dynamic + if(InpRiskDefaultSize==RISK_DEFAULT_AUTO) + { + //If the stop loss is not zero then calculate the lot size + if(SL!=0) + { + double RiskBaseAmount=0; + Print("Compute lot size"); + + //TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty + double TickValue=SymbolInfoDouble(gSymbol,SYMBOL_TRADE_TICK_VALUE); + //Define the base for the risk calculation depending on the parameter chosen + if(InpRiskBase==RISK_BASE_BALANCE) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE); + if(InpRiskBase==RISK_BASE_EQUITY) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY); + if(InpRiskBase==RISK_BASE_FREEMARGIN) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN); + + //Calculate the Position Size + gLotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue)); + + Print("(RiskBaseAmount ", RiskBaseAmount, " InpMaxRiskPerTrade ", InpMaxRiskPerTrade, " SL ", SL, " TickValue ", TickValue); + } + + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + gLotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + gLotSize=MathFloor(gLotSize/SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP); + + Print("LotSize ", gLotSize); +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(gLotSize>SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)) + gLotSize=SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX); + Print("Lot ", gLotSize, " Max lot ", SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)); + + Print("LotSize2 ", gLotSize); +//If the lot size is too small then set it to 0 and don't trade + if(gLotSizeInpMaxStopLoss) + { + gIsPreChecksOk=false; + Print("Default Stop Loss must be between Minimum and Maximum Stop Loss Allowed"); + return; + } +//Check if the default take profit you are setting in above the minimum and below the maximum + if(InpDefaultTakeProfitInpMaxTakeProfit) + { + gIsPreChecksOk=false; + Print("Default Take Profit must be between Minimum and Maximum Take Profit Allowed"); + return; + } +//Check if the Lot Size is between the minimum and maximum + if(InpDefaultLotSizeInpMaxLotSize) + { + gIsPreChecksOk=false; + Print("Default Lot Size must be between Minimum and Maximum Lot Size Allowed"); + return; + } +//Slippage must be >= 0 + if(InpSlippage<0) + { + gIsPreChecksOk=false; + Print("Slippage must be a positive value"); + return; + } +//MaxSpread must be >= 0 + if(InpMaxSpread<0) + { + gIsPreChecksOk=false; + Print("Maximum Spread must be a positive value"); + return; + } +//MaxRiskPerTrade is a % between 0 and 100 + if(InpMaxRiskPerTrade<0 || InpMaxRiskPerTrade>100) + { + gIsPreChecksOk=false; + Print("Maximum Risk Per Trade must be a percentage between 0 and 100"); + return; + } +//Spread is acceptable + long SpreadCurr=(int)Spread; + Print("Spread ", Spread); + if(SpreadCurr>InpMaxSpread) + { + gIsPreChecksOk=false; + Print("Spread is higher than Max acceptable spread"); + return; + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/CandleCount/ScanPositions.mqh b/Include/Nkanven/CandleCount/ScanPositions.mqh new file mode 100644 index 0000000..02076cf --- /dev/null +++ b/Include/Nkanven/CandleCount/ScanPositions.mqh @@ -0,0 +1,45 @@ +//+------------------------------------------------------------------+ +//| ScanPositions.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +//Scan all positions to find the ones submitted by the EA +//NOTE This function is defined as bool because we want to return true if it is successful and false if it fails +void ScanPositions() + { + +//Scan all the orders, retrieving some of the details + gTotalPositions = PositionsTotal(); + gTotalBuyPositions = 0; + gTotalSellPositions = 0; + + for(int i=0; i= InpDayTradingHourStart ", InpDayTradingHourStart ," ", dt.hour >= InpDayTradingHourStart); + Print("dt.hour ", dt.hour," <= InpDayTradingHourEnd ", InpDayTradingHourEnd ," ", dt.hour <= InpDayTradingHourEnd); + + //Check day trading hours + if(dt.hour >= InpDayTradingHourStart && dt.hour <= InpDayTradingHourEnd) + { + day_trading = true; + gIsOperatingHours=true; + Print("Day period trading"); + return; + } + + } +Print("InpTradingPeriods == NIGHT_TRADING ", InpTradingPeriods == NIGHT_TRADING); + if(InpTradingPeriods == NIGHT_TRADING) + { + //Check night trading hours + if(dt.hour >= InpNightTradingHourStart && dt.hour <= InpNightTradingHourEnd) + { + night_trading = true; + gIsOperatingHours=true; + Print("Night period trading"); + return; + } + } + + if(InpTradingPeriods == DAY_NIGHT_TRADING) + { + //Check night trading hours + if(day_trading || night_trading) + { + gIsOperatingHours=true; + Print("Day and night periods trading"); + return; + } + } + } +//+------------------------------------------------------------------+