diff --git a/.gitignore b/.gitignore index 5f02364..77fcfb6 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,10 @@ Thumbs.db *.mov *.wmv +# VS folder + .vscode/ + +# MT4/MT5 files MT4/MT5 files Files/ @@ -59,4 +63,21 @@ Presets/ Profiles/ Scripts/ Services/ +Shared Projets/ + +*.dat +Experts/Advisors/ +Experts/Examples/ +Include/Arrays/ +Include/C* +Include/Expert/ +Include/Files/ +Include/G* +Include/I +Include/M* +Include/O* +Include/S* +Include/T* +Include/W* +Include/V* Shared Projects/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5031bff --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "*.mqh": "cpp" + } +} \ No newline at end of file diff --git a/Experts/Nkanven/AreaBreaker.ex5 b/Experts/Nkanven/AreaBreaker.ex5 new file mode 100644 index 0000000..1fa1926 Binary files /dev/null and b/Experts/Nkanven/AreaBreaker.ex5 differ diff --git a/Experts/Nkanven/AreaBreaker.mq5 b/Experts/Nkanven/AreaBreaker.mq5 new file mode 100644 index 0000000..8b4d706 --- /dev/null +++ b/Experts/Nkanven/AreaBreaker.mq5 @@ -0,0 +1,267 @@ +//+------------------------------------------------------------------+ +//| AreaBreaker.mq5 | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" +#property version "1.00" + +#include // Description of variables +#include // Error library +#include // Prechecks +#include // +#include +#include // Scan for opened positions +#include //Check transaction history +#include //Manage trade dynamic open and close conditions +#include // Check buy and sell entries signals and execute them +#include // Lot size calculate +//#include //Draw trading range boundaries on chart +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +//Zigzag drawing inputs +string prefix = "SRLevel_"; //Object name prefix +color lineColor = clrYellow; +int lineWeight = 2; + +double SRLevels[]; +double Buffer[]; +int Handle; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + Handle = iCustom(Symb, PERIOD_CURRENT, "Examples\\ZigZag", Depth, Deviation, Backstep); + if(Handle==INVALID_HANDLE) + { + Print("Could not create a handle to ZigZag indicator"); + return(INIT_FAILED); + } + +//Clean up any SR levels left from earlier indicators + ObjectsDeleteAll(0, prefix, 0, OBJ_HLINE); + ChartRedraw(0); + ArrayResize(SRLevels, LookBack); +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + IndicatorRelease(Handle); + ObjectsDeleteAll(0, prefix, 0, OBJ_HLINE); + ChartRedraw(0); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + ArraySetAsSeries(Buffer,true); + + CopyBuffer(Handle, 0, 0, 3, Buffer); + if(candleChanged()) + if(Buffer[0]>0) + Print("Zigzag level ", Buffer[0]); +//DrawLevels(); + +SymbolInfoTick(_Symbol,last_tick); + + if(!ScanPositions()) + return; + + CheckHistory(); + CheckSpread(); + EvaluateEntry(); + ProfitRunner(); + CloseOpenPositions(); + ExecuteEntry(); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +/* +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//One time convert points to a price gap + static double levelGap = GapPoint*SymbolInfoDouble(Symb, SYMBOL_POINT); + + if(rates_total ==prev_calculated) + return(rates_total); + +//Get most recent lookback peaks + double zz =0; + double zzPeaks[]; + int zzCount = 0; + + ArrayResize(zzPeaks, LookBack); + ArrayInitialize(zzPeaks, 0.0); + + int count = CopyBuffer(Handle, 0, 0, rates_total, Buffer); + + if(count < 0) + { + int err = GetLastError(); + return(0); + } + + for(int i=1; i=0; i--) + { + price += zzPeaks[i]; + priceCount++; + if(i=0 || (zzPeaks[i]-zzPeaks[i-1]) > GapPoint) + { + if(priceCount >= Sensitivity) + { + price = price/priceCount; + SRLevels[srCounter] = price; + srCounter++; + } + price =0; + priceCount=0; + } + } + DrawLevels(); +//--- return value of prev_calculated for next call + return(rates_total); + } + +*/ +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void DrawLevels() + { + + for(int i=0; i +#include //EA paramters +#include //Trading hours checks +#include //Trading conditions checks +#include //Trading conditions checks +#include //Lot size calculator +#include //Lot size calculator +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +#include + +CiMA* sma; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + sma = new CiMA(); + sma.Create(gSymbol, InpTimeFrame, InpPeriods, InpAppliedPrice, InpMethod, PRICE_CLOSE); +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + TimeCurrent(dt); + + SymbolInfoTick(InpInstrument1,last_tick); + SymbolInfoTick(InpInstrument2, blast_tick); + + sma.Refresh(-1); + gSma = sma.Main(1); + + CheckOperationHours(); + CheckPreChecks(); + ScanPositions(); + + if(!gIsPreChecksOk) + return; + + Print("Good for trading..."); + ExecuteEntry(); + } +//+------------------------------------------------------------------+ diff --git a/Experts/Nkanven/Dam Launch.mq5 b/Experts/Nkanven/Dam Launch.mq5 new file mode 100644 index 0000000..1ca20f5 Binary files /dev/null and b/Experts/Nkanven/Dam Launch.mq5 differ diff --git a/Experts/Nkanven/EA_Template_1.0.mq5 b/Experts/Nkanven/EA_Template_1.0.mq5 new file mode 100644 index 0000000..4d0ffd2 --- /dev/null +++ b/Experts/Nkanven/EA_Template_1.0.mq5 @@ -0,0 +1,224 @@ +/* + + EA_Template.mq5 + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + + Description: + +*/ + +#property copyright "Copyright 2012-2020, Orchard Forex" +#property link "https://www.orchardforex.com" +#property version "1.00" +#property strict + +// +// This is where we pull in the framework +// +// Use the following line for the current framework +#include +// Use the following line for a specific framework (replace x.x) +//#include + +// +// Input Section +// + +// +// Some standard inputs, +// remember to change the default magic for each EA +// +input double InpVolume = 0.01; // Default order size +input string InpComment = __FILE__; // Default trade comment +input int InpMagicNumber = 20200701; // Magic Number + +// +// Declare the expert +// +#define CExpert CExpertBase +CExpert *Expert; + +// +// Indicators +// +CIndicatorBase *Indicator1; + +// +// Signals +// +CSignalBase *EntrySignal; +CSignalBase *ExitSignal; + +// +// TPSL - use child class names instead of CTPSLBase +// +CTPSLBase *TPObject; +CTPSLBase *SLObject; + +// +// Indicators for TPSL - use child class names instead of CIndicatorBase +// +CIndicatorBase *IndicatorTPSL1; +CIndicatorBase *IndicatorTPSL2; + + + +int OnInit() { + + // + // Instantiate the expert, use the child class name + // + Expert = new CExpert(); + + // + // Assign the default values to the expert + // + Expert.SetVolume(InpVolume); + Expert.SetTradeComment(InpComment); + Expert.SetMagic(InpMagicNumber); + + // + // Set up the indicators + // + Indicator1 = new CIndicatorBase(); + + // + // Set up the signals + // + EntrySignal = new CSignalBase(); + EntrySignal.AddIndicator(Indicator1, 0); + + ExitSignal = new CSignalBase(); + ExitSignal.AddIndicator(Indicator1, 0); + + // + // Add the signals to the expert + // + Expert.AddEntrySignal(EntrySignal); + Expert.AddExitSignal(ExitSignal); + + // + // If using fixed tp and sl set them here in points + // + Expert.SetTakeProfitValue(0); + Expert.SetStopLossValue(0); + + // + // Set up the Take Profit and Stop Loss objects + // Remember to create child class names, not base + // + TPObject = new CTPSLBase(); // Create the object + IndicatorTPSL1 = new CIndicatorBase(); // Create an indicator for the tp object + TPObject.AddIndicator(IndicatorTPSL1, 0); // Add the indicator to tp + // Set any other properties needed + + // And for the SL object + SLObject = new CTPSLBase(); + IndicatorTPSL2 = new CIndicatorBase(); + SLObject.AddIndicator(IndicatorTPSL2, 0); + + Expert.SetTakeProfitObj(TPObject); + Expert.SetStopLossObj(SLObject); + + // + // Finish expert initialisation and check result + // + int result = Expert.OnInit(); + + return(result); + +} + +void OnDeinit(const int reason) { + + EventKillTimer(); + + delete Expert; + delete ExitSignal; + delete EntrySignal; + delete Indicator1; + delete TPObject; + delete SLObject; + delete IndicatorTPSL1; + delete IndicatorTPSL2; + + return; + +} + +void OnTick() { + + Expert.OnTick(); + return; + +} + +void OnTimer() { + + Expert.OnTimer(); + return; + +} + +void OnTrade() { + + Expert.OnTrade(); + return; + +} + +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) { + + Expert.OnTradeTransaction(trans, request, result); + return; + +} + +double OnTester() { + + return(Expert.OnTester()); + +} + +void OnTesterInit() { + + Expert.OnTesterInit(); + return; + +} + +void OnTesterPass() { + + Expert.OnTesterPass(); + return; + +} + +void OnTesterDeinit() { + + Expert.OnTesterDeinit(); + return; + +} + +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) { + + Expert.OnChartEvent(id, lparam, dparam, sparam); + return; + +} + +void OnBookEvent(const string &symbol) { + + Expert.OnBookEvent(); + return; + +} + diff --git a/Experts/Nkanven/Equilibrium.ex5 b/Experts/Nkanven/Equilibrium.ex5 new file mode 100644 index 0000000..f8b1208 Binary files /dev/null and b/Experts/Nkanven/Equilibrium.ex5 differ diff --git a/Experts/Nkanven/Equilibrium.mq5 b/Experts/Nkanven/Equilibrium.mq5 new file mode 100644 index 0000000..6a2c0f2 --- /dev/null +++ b/Experts/Nkanven/Equilibrium.mq5 @@ -0,0 +1,134 @@ +//+------------------------------------------------------------------+ +//| Equilibrium.mq5 | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +CiIchimoku* ichimoku; +CiADX* adx; +CiATR* atr; + +#include // Description of variables +#include // Error library +#include // Prechecks +#include // +#include +#include // Scan for opened positions +#include //Check transaction history +#include //Manage trade dynamic open and close conditions +#include // Check buy and sell entries signals and execute them +#include // Lot size calculate +//#include //Draw trading range boundaries on chart +#include // Close opened positions + +//TODO: Add ADX to filter ranging market +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + ichimoku = new CiIchimoku(); + ichimoku.Create(Symb, PERIOD_CURRENT, tenkan_sen, kijun_sen, senkou_span_b); + + atr = new CiATR(); + atr.Create(Symb, PERIOD_CURRENT, atr_period); +// adx = new CiADX(); +// adx.Create(Symb, PERIOD_CURRENT, adx_period); +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- +ichimoku.Refresh(-1); +Tenkansen = ichimoku.TenkanSen(0); +Kijunsen = ichimoku.KijunSen(0); +Senkouspana = ichimoku.SenkouSpanA(-26); +Senkouspanb = ichimoku.SenkouSpanB(-26); +BwSenkouspana = ichimoku.SenkouSpanA(26); +BwSenkouspanb = ichimoku.SenkouSpanB(26); +Chinkouspan = ichimoku.ChinkouSpan(26); + +atr.Refresh(-1); +Atr = atr.Main(1); +/*adx.Refresh(-1); +AdxMain = adx.Main(1); +AdxPlus = adx.Plus(1); +AdxMinus = adx.Minus(1);*/ + +SymbolInfoTick(_Symbol,last_tick); +//ScanPositions scans all the opened positions and collect statistics, if an error occurs it skips to the next price change + + if(!ScanPositions()) + return; + CloseOpenPositions(); + CheckHistory(); + CheckSpread(); + EvaluateEntry(); + ProfitRunner(); + ExecuteEntry(); + + Comment( + "Expert Advisor by Anselme Nkondog (c) 2021\n"); + return; + } +//+------------------------------------------------------------------+ + +//Initialize variables +void InitializeVariables() + { + IsNewCandle=false; + IsTradedThisBar=false; + IsOperatingHours=false; + IsSpreadOK=false; + + LotSize=DefaultLotSize; + TickValue=0; + + TotalOpenBuy=0; + TotalOpenSell=0; + TotalOpenOrders=0; + + SignalEntry=SIGNAL_ENTRY_NEUTRAL; + SignalExit=SIGNAL_EXIT_NEUTRAL; + Print("Variables intialized"); + } + +//Check and return if the spread is not too high +void CheckSpread() + { +//Get the current spread in points, the (int) transforms the double coming from MarketInfo into an integer to avoid a warning when compiling + long SpreadCurr=Spread; + Print("Spread ", SpreadCurr); + if(SpreadCurr<=MaxSpread) + { + IsSpreadOK=true; + } + else + { + IsSpreadOK=false; + } + } +//+------------------------------------------------------------------+ diff --git a/Experts/Nkanven/Framework EA/Gervis.mq5 b/Experts/Nkanven/Framework EA/Gervis.mq5 new file mode 100644 index 0000000..36f92a1 --- /dev/null +++ b/Experts/Nkanven/Framework EA/Gervis.mq5 @@ -0,0 +1,197 @@ +/* + + MA Crossover.mq5 + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + + Description: + +*/ + +#property copyright "Copyright 2013-2020, Orchard Forex" +#property link "https://www.orchardforex.com" +#property version "1.00" +#property strict + +// +// This is where we pull in the framework +// +#include + +// +// Input Section +// +// Fast moving average +input int InpFastPeriods = 10; // Fast periods +input ENUM_MA_METHOD InpFastMethod = MODE_SMA; // Fast method +input ENUM_APPLIED_PRICE InpFastAppliedPrice = PRICE_CLOSE; // Fast price + +// Slow moving average +input int InpSlowPeriods = 20; // Slow periods +input ENUM_MA_METHOD InpSlowMethod = MODE_SMA; // Slow method +input ENUM_APPLIED_PRICE InpSlowAppliedPrice = PRICE_CLOSE; // Slow price + +// Bar numbers for comparison +//input int InpBar2 = 2; // Base bar number +//input int InpBar1 = 1; // Crossover bar number + +// +// Some standard inputs, +// remember to change the default magic for each EA +// +input double InpVolume = 0.01; // Default order size +input string InpComment = __FILE__; // Default trade comment +input int InpMagicNumber = 20200701; // Magic Number + +// +// Declare the expert, use the child class name +// +#define CExpert CExpertBase +CExpert *Expert; + +// +// Signals, use the child class names if applicable +// +CSignalBase *EntrySignal; +CSignalBase *ExitSignal; + +// +// Indicators - use the child class name here +// +CIndicatorMA *FastIndicator; +CIndicatorMA *SlowIndicator; + +int OnInit() { + + // + // Instantiate the expert + // + Expert = new CExpert(); + + // + // Assign the default values to the expert + // + Expert.SetVolume(InpVolume); + Expert.SetTradeComment(InpComment); + Expert.SetMagic(InpMagicNumber); + + // + // Create the indicators + // + FastIndicator = new CIndicatorMA(InpFastPeriods, 0, InpFastMethod, InpFastAppliedPrice); + SlowIndicator = new CIndicatorMA(InpSlowPeriods, 0, InpSlowMethod, InpSlowAppliedPrice); + + // + // Set up the signals + // + EntrySignal = new CSignalCrossover(); + EntrySignal.AddIndicator(FastIndicator, 0); + EntrySignal.AddIndicator(SlowIndicator, 0); + + //ExitSignal = Not needed, using the same signal as entry + + // + // Add the signals to the expert + // + Expert.AddEntrySignal(EntrySignal); + Expert.AddExitSignal(EntrySignal); // Same signal + + // + // Finish expert initialisation and check result + // + int result = Expert.OnInit(); + + return(result); + +} + +void OnDeinit(const int reason) { + + EventKillTimer(); + + delete Expert; + //delete ExitSignal; + delete EntrySignal; + delete FastIndicator; + delete SlowIndicator; + + return; + +} + +void OnTick() { + + Expert.OnTick(); + return; + +} + +void OnTimer() { + + Expert.OnTimer(); + return; + +} + +void OnTrade() { + + Expert.OnTrade(); + return; + +} + +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) { + + Expert.OnTradeTransaction(trans, request, result); + return; + +} + +double OnTester() { + + return(Expert.OnTester()); + +} + +void OnTesterInit() { + + Expert.OnTesterInit(); + return; + +} + +void OnTesterPass() { + + Expert.OnTesterPass(); + return; + +} + +void OnTesterDeinit() { + + Expert.OnTesterDeinit(); + return; + +} + +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) { + + Expert.OnChartEvent(id, lparam, dparam, sparam); + return; + +} + +void OnBookEvent(const string &symbol) { + + Expert.OnBookEvent(); + return; + +} + + diff --git a/Experts/Nkanven/Framework EA/GoldenDeparture/GDea.mq4 b/Experts/Nkanven/Framework EA/GoldenDeparture/GDea.mq4 new file mode 100644 index 0000000..4492408 --- /dev/null +++ b/Experts/Nkanven/Framework EA/GoldenDeparture/GDea.mq4 @@ -0,0 +1,153 @@ +/* + + MA Crossover.mq4 + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + + Description: + +*/ + +#property copyright "Copyright 2013-2020, Orchard Forex" +#property link "https://www.orchardforex.com" +#property version "1.00" +#property strict + +// +// This is where we pull in the framework +// +#include + +// +// Input Section +// +// Fast moving average +input int InpFastPeriods = 10; // Fast periods +input ENUM_MA_METHOD InpFastMethod = MODE_SMA; // Fast method +input ENUM_APPLIED_PRICE InpFastAppliedPrice = PRICE_CLOSE; // Fast price + +// Slow moving average +input int InpSlowPeriods = 20; // Slow periods +input ENUM_MA_METHOD InpSlowMethod = MODE_SMA; // Slow method +input ENUM_APPLIED_PRICE InpSlowAppliedPrice = PRICE_CLOSE; // Slow price + +// Bar numbers for comparison +//input int InpBar2 = 2; // Base bar number +//input int InpBar1 = 1; // Crossover bar number + +// +// Some standard inputs, +// remember to change the default magic for each EA +// +input double InpVolume = 0.01; // Default order size +input string InpComment = __FILE__; // Default trade comment +input int InpMagicNumber = 20200701; // Magic Number + +// +// Declare the expert, use the child class name +// +#define CExpert CExpertBase +CExpert *Expert; + +// +// Signals, use the child class names if applicable +// +CSignalBase *EntrySignal; +CSignalBase *ExitSignal; + +// +// Indicators - use the child class name here +// +CIndicatorMA *FastIndicator; +CIndicatorMA *SlowIndicator; + +int OnInit() { + + // + // Instantiate the expert + // + Expert = new CExpert(); + + // + // Assign the default values to the expert + // + Expert.SetVolume(InpVolume); + Expert.SetTradeComment(InpComment); + Expert.SetMagic(InpMagicNumber); + + // + // Create the indicators + // + FastIndicator = new CIndicatorMA(InpFastPeriods, 0, InpFastMethod, InpFastAppliedPrice); + SlowIndicator = new CIndicatorMA(InpSlowPeriods, 0, InpSlowMethod, InpSlowAppliedPrice); + + // + // Set up the signals + // + EntrySignal = new CSignalCrossover(); + EntrySignal.AddIndicator(FastIndicator, 0); + EntrySignal.AddIndicator(SlowIndicator, 0); + + //ExitSignal = Not needed, using the same signal as entry + + // + // Add the signals to the expert + // + Expert.AddEntrySignal(EntrySignal); + Expert.AddExitSignal(EntrySignal); // Same signal + + // + // Finish expert initialisation and check result + // + int result = Expert.OnInit(); + + return(result); + +} + +void OnDeinit(const int reason) { + + EventKillTimer(); + + delete Expert; + //delete ExitSignal; + delete EntrySignal; + delete FastIndicator; + delete SlowIndicator; + + return; + +} + +void OnTick() { + + Expert.OnTick(); + return; + +} + +void OnTimer() { + + Expert.OnTimer(); + return; + +} + +double OnTester() { + + return(Expert.OnTester()); + +} + +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) { + + Expert.OnChartEvent(id, lparam, dparam, sparam); + return; + +} + + diff --git a/Experts/Nkanven/Framework EA/GoldenDeparture/GDea.mq5 b/Experts/Nkanven/Framework EA/GoldenDeparture/GDea.mq5 new file mode 100644 index 0000000..fcacfe4 --- /dev/null +++ b/Experts/Nkanven/Framework EA/GoldenDeparture/GDea.mq5 @@ -0,0 +1,197 @@ +/* + + MA Crossover.mq5 + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + + Description: + +*/ + +#property copyright "Copyright 2013-2020, Orchard Forex" +#property link "https://www.orchardforex.com" +#property version "1.00" +#property strict + +// +// This is where we pull in the framework +// +#include + +// +// Input Section +// +// Fast moving average +input int InpFastPeriods = 10; // Fast periods +input ENUM_MA_METHOD InpFastMethod = MODE_SMA; // Fast method +input ENUM_APPLIED_PRICE InpFastAppliedPrice = PRICE_CLOSE; // Fast price + +// Slow moving average +input int InpSlowPeriods = 20; // Slow periods +input ENUM_MA_METHOD InpSlowMethod = MODE_SMA; // Slow method +input ENUM_APPLIED_PRICE InpSlowAppliedPrice = PRICE_CLOSE; // Slow price + +// Bar numbers for comparison +//input int InpBar2 = 2; // Base bar number +//input int InpBar1 = 1; // Crossover bar number + +// +// Some standard inputs, +// remember to change the default magic for each EA +// +input double InpVolume = 0.01; // Default order size +input string InpComment = __FILE__; // Default trade comment +input int InpMagicNumber = 20200701; // Magic Number + +// +// Declare the expert, use the child class name +// +#define CExpert CExpertBase +CExpert *Expert; + +// +// Signals, use the child class names if applicable +// +CSignalBase *EntrySignal; +CSignalBase *ExitSignal; + +// +// Indicators - use the child class name here +// +CIndicatorMA *FastIndicator; +CIndicatorMA *SlowIndicator; + +int OnInit() { + + // + // Instantiate the expert + // + Expert = new CExpert(); + + // + // Assign the default values to the expert + // + Expert.SetVolume(InpVolume); + Expert.SetTradeComment(InpComment); + Expert.SetMagic(InpMagicNumber); + + // + // Create the indicators + // + FastIndicator = new iMA(Symbol(), PERIOD_CURRENT, InpFastPeriods, 0, InpFastMethod, InpFastAppliedPrice); + SlowIndicator = new iMA(Symbol(), PERIOD_CURRENT, InpSlowPeriods, 0, InpSlowMethod, InpSlowAppliedPrice); + + // + // Set up the signals + // + EntrySignal = new CSignalCrossover(); + EntrySignal.AddIndicator(FastIndicator, 0); + EntrySignal.AddIndicator(SlowIndicator, 0); + + //ExitSignal = Not needed, using the same signal as entry + + // + // Add the signals to the expert + // + Expert.AddEntrySignal(EntrySignal); + Expert.AddExitSignal(EntrySignal); // Same signal + + // + // Finish expert initialisation and check result + // + int result = Expert.OnInit(); + + return(result); + +} + +void OnDeinit(const int reason) { + + EventKillTimer(); + + delete Expert; + //delete ExitSignal; + delete EntrySignal; + delete FastIndicator; + delete SlowIndicator; + + return; + +} + +void OnTick() { + + Expert.OnTick(); + return; + +} + +void OnTimer() { + + Expert.OnTimer(); + return; + +} + +void OnTrade() { + + Expert.OnTrade(); + return; + +} + +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) { + + Expert.OnTradeTransaction(trans, request, result); + return; + +} + +double OnTester() { + + return(Expert.OnTester()); + +} + +void OnTesterInit() { + + Expert.OnTesterInit(); + return; + +} + +void OnTesterPass() { + + Expert.OnTesterPass(); + return; + +} + +void OnTesterDeinit() { + + Expert.OnTesterDeinit(); + return; + +} + +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) { + + Expert.OnChartEvent(id, lparam, dparam, sparam); + return; + +} + +void OnBookEvent(const string &symbol) { + + Expert.OnBookEvent(); + return; + +} + + diff --git a/Experts/Nkanven/Framework EA/Grid/GridEA.ex5 b/Experts/Nkanven/Framework EA/Grid/GridEA.ex5 index 72df996..27a545f 100644 Binary files a/Experts/Nkanven/Framework EA/Grid/GridEA.ex5 and b/Experts/Nkanven/Framework EA/Grid/GridEA.ex5 differ diff --git a/Experts/Nkanven/Framework EA/Grid/SnT Bot.ex5 b/Experts/Nkanven/Framework EA/Grid/SnT Bot.ex5 new file mode 100644 index 0000000..40a16b7 Binary files /dev/null and b/Experts/Nkanven/Framework EA/Grid/SnT Bot.ex5 differ diff --git a/Experts/Nkanven/Framework EA/Grid/GridEA.mq5 b/Experts/Nkanven/Framework EA/Grid/SnT Bot.mq5 similarity index 86% rename from Experts/Nkanven/Framework EA/Grid/GridEA.mq5 rename to Experts/Nkanven/Framework EA/Grid/SnT Bot.mq5 index 396696b..d9d57a6 100644 --- a/Experts/Nkanven/Framework EA/Grid/GridEA.mq5 +++ b/Experts/Nkanven/Framework EA/Grid/SnT Bot.mq5 @@ -1,12 +1,11 @@ //+------------------------------------------------------------------+ -//| GridEA.mq5 | +//| SnT Bot.mq5 | //| Copyright 2021, Nkondog Anselme Venceslas | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, Nkondog Anselme Venceslas" -#property link "https://www.mql5.com" -#property version "1.00" - +#property link "https://www.salixnigra.com" +#property version "1.0" #include @@ -19,33 +18,34 @@ input string Comment_strategy="=========="; //Entry And //Add in this section the parameters for the indicators used in your entry and exit //General input parameters -input string Comment_0="=========="; //Risk Management Settings +input string Comment_0="=========="; //Risk Management Settings input ENUM_RISK_DEFAULT_SIZE InpRiskDefaultSize=RISK_DEFAULT_AUTO; //Position Size Mode input double InpDefaultLotSize=1; //Position Size (if fixed or if no stop loss defined) input ENUM_RISK_BASE InpRiskBase=RISK_BASE_BALANCE; //Risk Base input double InpMaxRiskPerTrade=0.5; //Percentage To Risk Each Trade +input double InpProfitPercent=1; input double InpMinLotSize=0.01; //Min Lot Size input double InpMaxLotSize=100; //Max Lot Size -input string Comment_1="=========="; //Trading Hours Settings +input string Comment_1="=========="; //Trading Hours Settings input bool InpUseTradingHours=false; //Activate Trading Hours input string InpTradingHourStart="01"; //Trading Start Hour (Broker Server Hour) input string InpTradingStartMin="30"; //Trading Start minute input string InpTradingHourEnd="23"; //Trading End Hour (Broker Server Hour) input string InpTradingEndMin="00"; //Trading End minute input bool InpUseTradingSession=true; -input ENUM_TRADING_SESSION InpTradingSession = LONDON_SESSION; //Trading session +input ENUM_TRADING_SESSION InpTradingSession = LONDON_SESSION; //Trading session -input string Comment_2="=========="; //Trading Hours Settings +input string Comment_2="=========="; //Trading Hours Settings input int InpGridGap = 1000; -input double InpVolume = 0.01; // Default order size -input string InpComment = __FILE__; // Default trade comment -input int InpMagicNumber = 20200701; // Magic Number -input int InpBrokerTimeZoneGMT = 2; //Broker timezone from GMT -input int InpSlippage = 2; - +input double InpVolume = 0.01; //Default order size +input string InpComment = __FILE__; //Default trade comment +input int InpMagicNumber = 20200701; //Magic Number +input int InpBrokerTimeZoneGMT = 2; //Broker timezone from GMT +input int InpSlippage = 2; //Slippage +input int not_used; int londonSession[] = {7, 17}; int newyorkSession[] = {13, 23}; @@ -96,23 +96,26 @@ int OnInit() Expert.SetRiskDefaultSize(InpRiskDefaultSize); Expert.SetUseTradingSession(InpTradingSession); Expert.SetSlippage(InpSlippage); + Expert.SetProfitPercent(InpProfitPercent); // // Set up the signals // - EntrySignal = new CSignalGrid(); + //EntrySignal = new CSignalGrid(); + //EntrySignal.SetMaxRiskPerTrade(InpMaxRiskPerTrade); + //EntrySignal.setMmagic(InpMagicNumber); //EntrySignal.AddIndicator(Indicator1, 0); - ExitSignal = new CSignalGrid(); - ExitSignal.SetMaxRiskPerTrade(InpMaxRiskPerTrade); - ExitSignal.setMmagic(InpMagicNumber); + //ExitSignal = new CSignalGrid(); + //ExitSignal.SetMaxRiskPerTrade(InpMaxRiskPerTrade); + //ExitSignal.setMmagic(InpMagicNumber); //ExitSignal.AddIndicator(Indicator1, 0); // // Add the signals to the expert // - Expert.AddEntrySignal(EntrySignal); - Expert.AddExitSignal(ExitSignal); + //Expert.AddEntrySignal(EntrySignal); + //Expert.AddExitSignal(ExitSignal); // // If using fixed tp and sl set them here in points @@ -213,7 +216,7 @@ void OnTradeTransaction(const MqlTradeTransaction& trans, //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ -double OnTester() +/*double OnTester() { return(Expert.OnTester()); @@ -252,7 +255,7 @@ void OnTesterDeinit() return; } - +*/ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ diff --git a/Experts/Nkanven/GDeaLite.ex5 b/Experts/Nkanven/GDeaLite.ex5 new file mode 100644 index 0000000..95ee4cc Binary files /dev/null and b/Experts/Nkanven/GDeaLite.ex5 differ diff --git a/Experts/Nkanven/GDeaLite.mq5 b/Experts/Nkanven/GDeaLite.mq5 new file mode 100644 index 0000000..dbb3948 --- /dev/null +++ b/Experts/Nkanven/GDeaLite.mq5 @@ -0,0 +1,115 @@ +//+------------------------------------------------------------------+ +//| GDeaLite.mq5 | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +CiMA* fsma; +CiMA* ssma; + +CiATR* atr; + +#include // Description of variables +#include // Error library +#include // Prechecks +#include // +#include +#include // Scan for opened positions +#include //Check transaction history +#include //Manage trade dynamic open and close conditions +#include // Check buy and sell entries signals and execute them +#include // Lot size calculate +#include // Close opened positions +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + fsma = new CiMA(); + ssma = new CiMA(); + + fsma.Create(gSymbol, PERIOD_CURRENT, InpFastPeriods, InpFastAppliedPrice, InpFastMethod, PRICE_CLOSE); + ssma.Create(gSymbol, PERIOD_CURRENT, InpSlowPeriods, InpFastAppliedPrice, InpSlowMethod, PRICE_CLOSE); + + atr = new CiATR(); + atr.Create(gSymbol, PERIOD_CURRENT, InpAtrPeriod); +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + fsma.Refresh(-1); + ssma.Refresh(-1); + + gSsma = ssma.Main(1); +//isQualifiedCandle(0); + OrderClose(); + if(!ScanPositions()) + return; + if(OrdersTotal()>0) + return; + CheckSpread(); + entryConditions(); + EvaluateEntry(); + ExecuteEntry(); + + Comment( + "Expert Advisor by Anselme Nkondog (c) 2021\n"); + + } +//+------------------------------------------------------------------+ + +//Initialize variables +void InitializeVariables() + { + gIsNewCandle=false; + gIsTradedThisBar=false; + gIsOperatingHours=false; + gIsSpreadOK=false; + + gLotSize=InpDefaultLotSize; + gTickValue=0; + + gTotalOpenBuy=0; + gTotalOpenSell=0; + + gSignalEntry=SIGNAL_ENTRY_NEUTRAL; + gSignalExit=SIGNAL_EXIT_NEUTRAL; + Print("Variables intialized"); + } + +//Check and return if the spread is not too high +void CheckSpread() + { +//Get the current spread in points, the (int) transforms the double coming from MarketInfo into an integer to avoid a warning when compiling + long SpreadCurr=SymbolInfoInteger(gSymbol, SYMBOL_SPREAD); + Print("Spread ", SpreadCurr); + if(SpreadCurr<=InpMaxSpread) + { + gIsSpreadOK=true; + } + else + { + gIsSpreadOK=false; + } + } +//+------------------------------------------------------------------+ diff --git a/Experts/Nkanven/GeminiHedge.ex5 b/Experts/Nkanven/GeminiHedge.ex5 new file mode 100644 index 0000000..90d9ade Binary files /dev/null and b/Experts/Nkanven/GeminiHedge.ex5 differ diff --git a/Experts/Nkanven/GeminiHedge.mq5 b/Experts/Nkanven/GeminiHedge.mq5 new file mode 100644 index 0000000..a6ba695 --- /dev/null +++ b/Experts/Nkanven/GeminiHedge.mq5 @@ -0,0 +1,81 @@ +//+------------------------------------------------------------------+ +//| GeminiHedge.mq5 | +//| Copyright 2022, Nkondog Anselme Venceslas. | +//| https://www.linkedin.com/in/nkondog | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, Nkondog Anselme Venceslas." +#property link "https://www.linkedin.com/in/nkondog" +#property version "1.00" +#include +#include //EA paramters +#include //Trading hours checks +#include //Trading conditions checks +#include //Trading conditions checks +#include //DCA manager +#include //Lot size calculator +#include //Trade entries manager +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + TimeCurrent(dt); + string instruments[]; + + if(InpActivateDCAHedging) + { + Print("DCA Hedging is activated"); + ArrayResize(instruments,2); + instruments[0] = InpInstrument1; + instruments[1] = InpInstrument2; + } + else + { + Print("DCA Hedging is not activated"); + ArrayResize(instruments,1); + instruments[0] = InpInstrument1; + } + + for(int i=0; i +#include + +CiMA* sma; +CiMA* ssma; + +#include // Description of variables +#include // Error library +#include // Prechecks +#include // +#include +#include // Scan for opened positions +#include //Check transaction history +#include //Manage trade dynamic open and close conditions +#include // Check buy and sell entries signals and execute them +#include // Lot size calculate +#include // Close opened positions +#include +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + //sma = new CiMA(); + //ssma = new CiMA(); + + //sma.Create(gSymbol, PERIOD_CURRENT, InpMAPeriods, InpMAAppliedPrice, InpMAMethod, PRICE_CLOSE); + //ssma.Create(gSymbol, PERIOD_CURRENT, 200, InpMAAppliedPrice, InpMAMethod, PRICE_CLOSE); + InitializeVariables(); +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + SymbolInfoTick(_Symbol,last_tick); + + TimeCurrent(dt); + + CheckOperationHours(); + +//isQualifiedCandle(0); + OrderClose(); + + ScanPositions(); + + CheckSpread(); + EvaluateEntry(); + ExecuteEntry(); + + Comment( + "Expert Advisor by Anselme Nkondog (c) 2021\n "+ + " Hour " + dt.hour + " Min "+ dt.min+"\n" + " Last Highest Price " + gLastHighestPrice + " Price %change "+ gPriceChange); + + } +//+------------------------------------------------------------------+ + +//Initialize variables +void InitializeVariables() + { + gIsNewCandle=false; + gIsTradedThisBar=false; + gIsOperatingHours=false; + gIsSpreadOK=false; + + gLotSize=InpDefaultLotSize; + gTickValue=0; + + gTotalOpenBuy=0; + gTotalOpenSell=0; + + gSignalEntry=SIGNAL_ENTRY_NEUTRAL; + gSignalExit=SIGNAL_EXIT_NEUTRAL; + Print("Variables intialized"); + } + +//Check and return if the spread is not too high +void CheckSpread() + { +//Get the current spread in points, the (int) transforms the double coming from MarketInfo into an integer to avoid a warning when compiling + long SpreadCurr=SymbolInfoInteger(gSymbol, SYMBOL_SPREAD); + Print("Spread ", SpreadCurr); + if(SpreadCurr<=InpMaxSpread) + { + gIsSpreadOK=true; + } + else + { + gIsSpreadOK=false; + } + } +//+------------------------------------------------------------------+ diff --git a/Experts/Nkanven/GridEA.ex5 b/Experts/Nkanven/GridEA.ex5 deleted file mode 100644 index 6eadeed..0000000 Binary files a/Experts/Nkanven/GridEA.ex5 and /dev/null differ diff --git a/Experts/Nkanven/HighTension.ex5 b/Experts/Nkanven/HighTension.ex5 new file mode 100644 index 0000000..e5d12ce Binary files /dev/null and b/Experts/Nkanven/HighTension.ex5 differ diff --git a/Experts/Nkanven/HighTension.mq5 b/Experts/Nkanven/HighTension.mq5 new file mode 100644 index 0000000..8314dc3 --- /dev/null +++ b/Experts/Nkanven/HighTension.mq5 @@ -0,0 +1,95 @@ +//+------------------------------------------------------------------+ +//| HighTension.mq5 | +//| Copyright 2022, Nkondog Anselme Venceslas. | +//| https://www.linkedin/in/nkondog.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, Nkondog Anselme Venceslas." +#property link "https://www.linkedin/in/nkondog.com" +#property version "1.00" + +#include +#include //EA paramters +#include //Trading conditions checks +#include //Trading conditions checks +#include //Lot size calculator +#include //Lot size calculator +#include //Emergency close of transaction +#include //Handle notification + +int handle; +const int indexMA = 0; +const int indexColor = 1; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + handle = iCustom(gSymbol, PERIOD_CURRENT, "Nkanven\MA-Slope", InpPeriods, InpMethod, InpAppliedPrice); + + if(handle == INVALID_HANDLE) + { + PrintFormat("Error %i ", GetLastError()); + return(INIT_FAILED); + } +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + IndicatorRelease(handle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + TimeCurrent(dt); + + SymbolInfoTick(_Symbol,last_tick); + + CheckPreChecks(); + Comment("Spread ", DoubleToString(Spread,0)); + if(!gIsPreChecksOk) + return; + +//Print("TF", PERIOD_CURRENT, " 1min ", PERIOD_M1, " 5min ", PERIOD_M5, " Period ", Period()); + /*ScanPositions();*/ + if(!newBar()) + return; + + int cnt = CopyBuffer(handle, indexMA, 0, 3, bufferMA); + if(cnt<3) + return; + cnt = CopyBuffer(handle, indexColor, 0, 3, bufferColor); + + currentMA = bufferMA[1]; + currentColor = bufferColor[1]; + + CloseTransactions(); + ExecuteEntry(); + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool newBar() + { + + static datetime prevTime = 0; + datetime currentTime = iTime(gSymbol, PERIOD_CURRENT, 0); + if(currentTime != prevTime) + { + prevTime = currentTime; + return(true); + } + return(false); + } +//+------------------------------------------------------------------+ diff --git a/Experts/Nkanven/Lotcal.ex5 b/Experts/Nkanven/Lotcal.ex5 new file mode 100644 index 0000000..422b8c4 Binary files /dev/null and b/Experts/Nkanven/Lotcal.ex5 differ diff --git a/Experts/Nkanven/Lotcal.mq5 b/Experts/Nkanven/Lotcal.mq5 new file mode 100644 index 0000000..b9b29a4 Binary files /dev/null and b/Experts/Nkanven/Lotcal.mq5 differ diff --git a/Experts/Nkanven/MAGrid.ex5 b/Experts/Nkanven/MAGrid.ex5 new file mode 100644 index 0000000..42f8cbf Binary files /dev/null and b/Experts/Nkanven/MAGrid.ex5 differ diff --git a/Experts/Nkanven/MAGrid.mq5 b/Experts/Nkanven/MAGrid.mq5 new file mode 100644 index 0000000..6e0b26c --- /dev/null +++ b/Experts/Nkanven/MAGrid.mq5 @@ -0,0 +1,148 @@ +//+------------------------------------------------------------------+ +//| MAGrid.mq5 | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" +#property version "1.00" + +// Moving Average grid strategy +/* +Set pending orders x point above and below price. +If price above SMA, buy and set buy orders x time the ATR above and below price. +If price below SMA, sell and set sell orders x time the ATR above and below price. +Close all position at the close of the first candle crossing the moving average. + +Open positions and set orders if there's nothing. At take profit, close all pending orders and reopen others +*/ +#include +#include +CiMA* ma; +CiATR* atr; + +#include // Description of variables +//#include // Error library +//#include // Prechecks +//#include // +#include +#include // Scan for opened positions +//#include //Check transaction history +//#include //Manage trade dynamic open and close conditions +#include // Check buy and sell entries signals and execute them +#include // Lot size calculate +#include // Close opened positions + + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + ma = new CiMA(); + ma.Create(gSymbol, PERIOD_CURRENT, InpFastPeriods, InpFastAppliedPrice, InpFastMethod, PRICE_CLOSE); + + atr = new CiATR(); + atr.Create(gSymbol, PERIOD_CURRENT, InpAtrPeriod); +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + SymbolInfoTick(_Symbol,last_tick); + +//Get technical indicators values + ma.Refresh(-1); + gMa = ma.Main(1); + + atr.Refresh(-1); + gAtr = atr.Main(1); + +//Initial position scanning + ScanPositions(); + + Print("Price is below SMA. Price = ", iClose(gSymbol, PERIOD_CURRENT, 1), " SMA = ", gMa, " Total buy ", gTotalBuyPositions); + +//Check closing signal + +//Close all buy position and orders if price is below MA + if(iClose(gSymbol, PERIOD_CURRENT, 1) < gMa && gTotalTransactions > 0) + { + Print("Price is below SMA. Price = ", iClose(gSymbol, PERIOD_CURRENT, 1), " SMA = ", gMa); + CloseTransactions(SIGNAL_EXIT_BUY); + } + else + { + //Close all sell positions and orders if price is above MA + if(iClose(gSymbol, PERIOD_CURRENT, 1) > gMa && gTotalTransactions > 0) + { + Print("Price is above SMA. Price = ", iClose(gSymbol, PERIOD_CURRENT, 1), " SMA = ", gMa); + CloseTransactions(SIGNAL_EXIT_SELL); + } + } + +//Rescan positions + ScanPositions(); + + Print("Total transaction ", gTotalTransactions, " gTotalBuyPositions ", gTotalBuyPositions); +//Do not open positions if there are positions or orders pending + if(gTotalTransactions>0) + { + //If there's no position, close all pending orders + if(gTotalBuyPositions == 0 && gTotalTransactions > 0) + { + Print("Delete all"); + CloseTransactions(SIGNAL_EXIT_ALL); + } + else + { + if(gTotalSellPositions==0 && gTotalTransactions >0) + { + CloseTransactions(SIGNAL_EXIT_ALL); + } + else + { + return; + } + } + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + CheckSpread(); + EvaluateEntry(); + ExecuteEntry(); +} +//+------------------------------------------------------------------+ + +//Check and return if the spread is not too high + void CheckSpread() + { + //Get the current spread in points, the (int) transforms the double coming from MarketInfo into an integer to avoid a warning when compiling + long SpreadCurr=SymbolInfoInteger(gSymbol, SYMBOL_SPREAD); + Print("Spread ", SpreadCurr); + if(SpreadCurr<=InpMaxSpread) + { + gIsSpreadOK=true; + } + else + { + gIsSpreadOK=false; + } + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ + diff --git a/Experts/Nkanven/MidNightAngel.ex5 b/Experts/Nkanven/MidNightAngel.ex5 new file mode 100644 index 0000000..e6614b3 Binary files /dev/null and b/Experts/Nkanven/MidNightAngel.ex5 differ diff --git a/Experts/Nkanven/MidNightAngel.mq5 b/Experts/Nkanven/MidNightAngel.mq5 new file mode 100644 index 0000000..902f220 Binary files /dev/null and b/Experts/Nkanven/MidNightAngel.mq5 differ diff --git a/Experts/Nkanven/NYMidnightBreak.ex5 b/Experts/Nkanven/NYMidnightBreak.ex5 new file mode 100644 index 0000000..b77fac1 Binary files /dev/null and b/Experts/Nkanven/NYMidnightBreak.ex5 differ diff --git a/Experts/Nkanven/NYMidnightBreak.mq5 b/Experts/Nkanven/NYMidnightBreak.mq5 new file mode 100644 index 0000000..81f58a8 --- /dev/null +++ b/Experts/Nkanven/NYMidnightBreak.mq5 @@ -0,0 +1,53 @@ +//+------------------------------------------------------------------+ +//| NYMidnightBreak.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 // EA paramters +#include // Lot size calculator + +#define SECONDSINADAY 86400 +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- +//--- The date is on Sunday + datetime time=D'2002.04.25 12:00'; + string symbol="GBPUSD"; + ENUM_TIMEFRAMES tf=PERIOD_H1; + bool exact=false; +//--- If there is no bar at the specified time, iBarShift will return the index of the nearest bar + int bar_index=iBarShift(symbol,tf,time,exact); +//--- Check the error code after the call of iBarShift() + +datetime Midnight, StartOfNewYear; + + + Midnight = TimeCurrent() - ( TimeCurrent()%SECONDSINADAY ); // midnight today as a datetime + Print(" Hour ", dt.hour, " midnight " , Midnight); + } +//+------------------------------------------------------------------+ diff --git a/Experts/Nkanven/NewCandleAlert.ex5 b/Experts/Nkanven/NewCandleAlert.ex5 new file mode 100644 index 0000000..5d57564 Binary files /dev/null and b/Experts/Nkanven/NewCandleAlert.ex5 differ diff --git a/Experts/Nkanven/NewCandleAlert.mq5 b/Experts/Nkanven/NewCandleAlert.mq5 new file mode 100644 index 0000000..f55f84f --- /dev/null +++ b/Experts/Nkanven/NewCandleAlert.mq5 @@ -0,0 +1,50 @@ +//+------------------------------------------------------------------+ +//| NewCandleAlert.mq5 | +//| Copyright 2022, Nkondog Anselme Venceslas. | +//| https://www.linkedin.com/in/nkondog | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, Nkondog Anselme Venceslas." +#property link "https://www.linkedin.com/in/nkondog" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + newBar(); + } +//+------------------------------------------------------------------+ + +bool newBar() + { + static datetime prevTime = 0; + datetime currentTime = iTime(Symbol(), PERIOD_CURRENT, 0); + if(currentTime != prevTime) + { + prevTime = currentTime; + + Alert("New candle"); + + return(true); + } + return(false); + } \ No newline at end of file diff --git a/Experts/Nkanven/Sessions.ex5 b/Experts/Nkanven/Sessions.ex5 new file mode 100644 index 0000000..148d759 Binary files /dev/null and b/Experts/Nkanven/Sessions.ex5 differ diff --git a/Experts/Nkanven/Sessions.mq5 b/Experts/Nkanven/Sessions.mq5 new file mode 100644 index 0000000..3d091a3 Binary files /dev/null and b/Experts/Nkanven/Sessions.mq5 differ diff --git a/Experts/Nkanven/StarRiskCalculator.ex5 b/Experts/Nkanven/StarRiskCalculator.ex5 new file mode 100644 index 0000000..769e576 Binary files /dev/null and b/Experts/Nkanven/StarRiskCalculator.ex5 differ diff --git a/Experts/Nkanven/StarRiskCalculator.mq5 b/Experts/Nkanven/StarRiskCalculator.mq5 new file mode 100644 index 0000000..b353e6b --- /dev/null +++ b/Experts/Nkanven/StarRiskCalculator.mq5 @@ -0,0 +1,216 @@ +//+------------------------------------------------------------------+ +//| StarRiskCalculator.mq5 | +//| Copyright 2022, Nkondog Anselme Venceslas. | +//| https://www.linkedin.com/in/nkondog | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, Nkondog Anselme Venceslas." +#property link "https://www.linkedin.com/in/nkondog" +#property version "1.00" + + +//Parameters +MqlTick last_tick; +//Enumerative for the base used for risk calculation +enum ENUM_RISK_BASE + { + RISK_BASE_EQUITY=1, //EQUITY + RISK_BASE_BALANCE=2, //BALANCE + RISK_BASE_FREEMARGIN=3, //FREE MARGIN + RISK_BASE_INPUT=4, //INPUT BASE + }; + +//Enumerative for the default risk size +enum ENUM_RISK_DEFAULT_SIZE + { + RISK_DEFAULT_FIXED=1, //FIXED SIZE + RISK_DEFAULT_AUTO=2, //AUTOMATIC SIZE BASED ON RISK + }; + +input ENUM_RISK_DEFAULT_SIZE InpRiskDefaultSize=RISK_DEFAULT_AUTO; //Position Size Mode +input double InpBalance=10000.0; //Balance +input double InpMaxLossPercent=4.0; //Max Account Risk % +input int InpLifeCount=20; //Number of losses +double InpDefaultLotSize=0.01; //Position Size (if fixed or if no stop loss defined) +input ENUM_RISK_BASE InpRiskBase=RISK_BASE_BALANCE; //Risk Base +//input double InpMaxRiskPerTrade=0.5; //Percentage To Risk Each Trade +double InpMinLotSize=0.01; //Minimum Position Size Allowed +double InpMaxLotSize=100; //Maximum Position Size Allowed +double RiskBaseAmount=0; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string Symb = Symbol(); +string AccountCurr = AccountInfoString(ACCOUNT_CURRENCY); +double MaxRiskPerTrade=0.0; //Percentage To Risk Each Trade +double LotSize=InpDefaultLotSize; +double price=0.0; +double risk=0.0; +double StoplossPips=0.0; +double riskDiff=0.0; +double initialLoss=0.0; +double totalLoss=0.0; +double maxRiskPerLife=0.0; + +//TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty +double TickValue=SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_VALUE); + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + Print("The Expert Advisor with name ",MQLInfoString(MQL_PROGRAM_NAME)," is running"); +//--- enable object create events + ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true); +//--- enable object delete events + ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true); +//--- + return(INIT_SUCCEEDED); + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void OnTick() + { + + LotSizeCalculate(price); + riskDiff = NormalizeDouble(RiskBaseAmount - InpBalance, 2); + initialLoss = (InpBalance * InpMaxLossPercent) / 100; + totalLoss = NormalizeDouble(riskDiff + initialLoss, 2); + maxRiskPerLife = NormalizeDouble(totalLoss /InpLifeCount, 2); + MaxRiskPerTrade = NormalizeDouble((maxRiskPerLife * 100) / RiskBaseAmount, 2); + + Comment("Star Risk Calculator \nRiskDiff: " + riskDiff + " " + AccountCurr +"\nInitialLoss: " + initialLoss + " " + AccountCurr +"\nTotalLoss: " + totalLoss + " " + AccountCurr +"\nMaxRiskPerLife: " + maxRiskPerLife + " " + AccountCurr + "\nMaxRiskPerTrade: " + MaxRiskPerTrade +"%"); + + +double StopAmount = StoplossPips * LotSize * TickValue; + + string text ="Lot size for "+ MaxRiskPerTrade +"% = " + DoubleToString(LotSize,2) + " lot (" + NormalizeDouble(StopAmount, 2) + " " + AccountCurr + ")"; + string name = "Lot"; + string name2 = "risk"; + ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); + //ObjectSetText(name,text, 36, "Corbel Bold", YellowGreen); + ObjectSetInteger(0,name, OBJPROP_CORNER, CORNER_RIGHT_UPPER); + ObjectSetInteger(0,name, OBJPROP_XDISTANCE, 550); + ObjectSetInteger(0,name, OBJPROP_YDISTANCE, 10); + ObjectSetString(0,name,OBJPROP_TEXT,text); + ObjectSetString(0,name,OBJPROP_FONT,"Arial"); + ObjectSetInteger(0,name,OBJPROP_FONTSIZE,14); + ObjectSetInteger(0,name,OBJPROP_COLOR,clrYellowGreen); + //LabelDelete(0, name); + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, // Event identifier + const long& lparam, // Event parameter of long type + const double& dparam, // Event parameter of double type + const string& sparam) // Event parameter of string type + { +//--- the object has been deleted + if(id==CHARTEVENT_OBJECT_DELETE) + { + Print("The object with name ",sparam," has been deleted"); + } +//--- the object has been created + if(id==CHARTEVENT_OBJECT_CREATE) + { + Print("The object with name ",sparam," has been created"); + } + +//--- the object has been moved or its anchor point coordinates has been changed + if(id==CHARTEVENT_OBJECT_DRAG) + { + price = ObjectGetDouble(0, sparam, OBJPROP_PRICE, 0); + Print("The anchor point coordinates of the object with name ",sparam," has been changed. Price ", price); + } + } + + +//Lot Size Calculator +void LotSizeCalculate(double stopLoss) + { + SymbolInfoTick(_Symbol,last_tick); + double SL=0; + double PriceAsk=last_tick.ask; + double PriceBid=last_tick.bid; + + if(stopLoss < PriceAsk) + { + SL = (PriceAsk-stopLoss)/_Point; + } + if(stopLoss > PriceAsk) + { + SL = (stopLoss-PriceBid)/_Point; + } + Print("Stop loss distance ", SL); + +//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) + { + //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); + if(InpRiskBase==RISK_BASE_INPUT) + RiskBaseAmount=InpBalance; + + //Calculate the Position Size + //Print("RiskBaseAmount ", RiskBaseAmount, " MaxRiskPerTrade ", InpMaxRiskPerTrade, "Stop loss ", SL, " TickValue ", TickValue); + + LotSize=((RiskBaseAmount*MaxRiskPerTrade/100)/(SL*TickValue)); + StoplossPips = SL; + + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>InpMaxLotSize) + LotSize=InpMaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX); + Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSize < SymbolInfoDouble(Symb,SYMBOL_VOLUME_MIN)) + { + LotSize=0; + Print("Lot size too small"); + } + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Delete a text label | +//+------------------------------------------------------------------+ +bool LabelDelete(const long chart_ID=0, // chart's ID + const string name="Label") // label name + { +//--- reset the error value + ResetLastError(); +//--- delete the label + if(!ObjectDelete(chart_ID,name)) + { + Print(__FUNCTION__, + ": failed to delete a text label! Error code = ",GetLastError()); + return(false); + } +//--- successful execution + return(true); + } \ No newline at end of file diff --git a/Experts/Nkanven/StarRiskCalculatorTrader.ex5 b/Experts/Nkanven/StarRiskCalculatorTrader.ex5 new file mode 100644 index 0000000..d5bce8c Binary files /dev/null and b/Experts/Nkanven/StarRiskCalculatorTrader.ex5 differ diff --git a/Experts/Nkanven/StarRiskCalculatorTrader.mq5 b/Experts/Nkanven/StarRiskCalculatorTrader.mq5 new file mode 100644 index 0000000..881fdc9 Binary files /dev/null and b/Experts/Nkanven/StarRiskCalculatorTrader.mq5 differ diff --git a/Experts/Nkanven/TheChallenger.ex5 b/Experts/Nkanven/TheChallenger.ex5 new file mode 100644 index 0000000..e13b8f1 Binary files /dev/null and b/Experts/Nkanven/TheChallenger.ex5 differ diff --git a/Experts/Nkanven/TheChallenger.mq5 b/Experts/Nkanven/TheChallenger.mq5 new file mode 100644 index 0000000..0746abe --- /dev/null +++ b/Experts/Nkanven/TheChallenger.mq5 @@ -0,0 +1,72 @@ +//+------------------------------------------------------------------+ +//| TheChallenger.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/Experts/Nkanven/TrendlinesEA.ex5 b/Experts/Nkanven/TrendlinesEA.ex5 new file mode 100644 index 0000000..05fe54b Binary files /dev/null and b/Experts/Nkanven/TrendlinesEA.ex5 differ diff --git a/Experts/Nkanven/TrendlinesEA.mq5 b/Experts/Nkanven/TrendlinesEA.mq5 new file mode 100644 index 0000000..cf60d90 Binary files /dev/null and b/Experts/Nkanven/TrendlinesEA.mq5 differ diff --git a/Experts/Nkanven/loggertest.ex5 b/Experts/Nkanven/loggertest.ex5 new file mode 100644 index 0000000..ef5694b Binary files /dev/null and b/Experts/Nkanven/loggertest.ex5 differ diff --git a/Experts/Nkanven/loggertest.mq5 b/Experts/Nkanven/loggertest.mq5 new file mode 100644 index 0000000..f970548 Binary files /dev/null and b/Experts/Nkanven/loggertest.mq5 differ diff --git a/Include/Nkanven/A_EntriesManagement.mqh b/Include/Nkanven/A_EntriesManagement.mqh new file mode 100644 index 0000000..893777e Binary files /dev/null and b/Include/Nkanven/A_EntriesManagement.mqh differ diff --git a/Include/Nkanven/A_HistoryChecker.mqh b/Include/Nkanven/A_HistoryChecker.mqh new file mode 100644 index 0000000..cce9256 Binary files /dev/null and b/Include/Nkanven/A_HistoryChecker.mqh differ diff --git a/Include/Nkanven/A_LotSizeCal.mqh b/Include/Nkanven/A_LotSizeCal.mqh new file mode 100644 index 0000000..79f5c11 --- /dev/null +++ b/Include/Nkanven/A_LotSizeCal.mqh @@ -0,0 +1,62 @@ +//+------------------------------------------------------------------+ +//| A_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(RiskDefaultSize==RISK_DEFAULT_AUTO) + { + //If the stop loss is not zero then calculate the lot size + if(SL!=0) + { + double RiskBaseAmount=0; + //TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty + TickValue=SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_VALUE); + //Define the base for the risk calculation depending on the parameter chosen + if(RiskBase==RISK_BASE_BALANCE) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE); + if(RiskBase==RISK_BASE_EQUITY) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY); + if(RiskBase==RISK_BASE_FREEMARGIN) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN); + //Calculate the Position Size + Print("Multiplier ", lotMultiplier, "Before lot multiplier ", (RiskBaseAmount*MaxRiskPerTrade/100)/(SL*TickValue)); + Print("RiskBaseAmount ", RiskBaseAmount, " MaxRiskPerTrade ", MaxRiskPerTrade, "Stop loss ", SL, " TickValue ", TickValue); + + LotSize=((RiskBaseAmount*MaxRiskPerTrade/100)/(SL*TickValue)); + + Print("After lot multiplier ", LotSize, " Lot multiplier ", lotMultiplier); + if(ActiveMartingale) + { + LotSize = LotSize * lotMultiplier; + } + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=DefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>MaxLotSize) + LotSize=MaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX); + Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSize < SymbolInfoDouble(Symb,SYMBOL_VOLUME_MIN)) + { + LotSize=0; + Print("Lot size too small"); + } + } diff --git a/Include/Nkanven/A_Parameters.mqh b/Include/Nkanven/A_Parameters.mqh new file mode 100644 index 0000000..42702da --- /dev/null +++ b/Include/Nkanven/A_Parameters.mqh @@ -0,0 +1,213 @@ +//+------------------------------------------------------------------+ +//| A_Parameters.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" +//+------------------------------------------------------------------+ +//| defines | +//+------------------------------------------------------------------+ + +//-ENUMERATIVE VARIABLES-// +//Enumerative variables are useful to associate numerical values to easy to remember strings +//It is similar to constants but also helps if the variable is set from the input page of the EA +//The text after the // is what you see in the input paramenters when the EA loads +//It is good practice to place all the enumberative at the start + +//Enumerative for the entry signal value +enum ENUM_SIGNAL_ENTRY + { + SIGNAL_ENTRY_NEUTRAL=0, //SIGNAL ENTRY NEUTRAL + SIGNAL_ENTRY_BUY=1, //SIGNAL ENTRY BUY + SIGNAL_ENTRY_SELL=-1, //SIGNAL ENTRY SELL + }; + +//Enumerative for the exit signal value +enum ENUM_SIGNAL_EXIT + { + SIGNAL_EXIT_NEUTRAL=0, //SIGNAL EXIT NEUTRAL + SIGNAL_EXIT_BUY=1, //SIGNAL EXIT BUY + SIGNAL_EXIT_SELL=-1, //SIGNAL EXIT SELL + SIGNAL_EXIT_ALL=2, //SIGNAL EXIT ALL + }; + +//Enumerative for the allowed trading direction +enum ENUM_TRADING_ALLOW_DIRECTION + { + TRADING_ALLOW_BOTH=0, //ALLOW BOTH BUY AND SELL + TRADING_ALLOW_BUY=1, //ALLOW BUY ONLY + TRADING_ALLOW_SELL=-1, //ALLOW SELL ONLY + }; + +//Enumerative for the base used for risk calculation +enum ENUM_RISK_BASE + { + RISK_BASE_EQUITY=1, //EQUITY + RISK_BASE_BALANCE=2, //BALANCE + RISK_BASE_FREEMARGIN=3, //FREE MARGIN + }; + +//Enumerative for the default risk size +enum ENUM_RISK_DEFAULT_SIZE + { + RISK_DEFAULT_FIXED=1, //FIXED SIZE + RISK_DEFAULT_AUTO=2, //AUTOMATIC SIZE BASED ON RISK + }; + +//Enumerative for the Stop Loss mode +enum ENUM_MODE_SL + { + SL_FIXED=0, //FIXED STOP LOSS + SL_AUTO=1, //AUTOMATIC STOP LOSS + }; + +//Enumerative for the Take Profit Mode +enum ENUM_MODE_TP + { + TP_FIXED=0, //FIXED TAKE PROFIT + TP_AUTO=1, //AUTOMATIC TAKE PROFIT + }; + +//Enumerative for the stop loss calculation +enum ENUM_MODE_SL_BY + { + SL_BY_POINTS=0, //STOP LOSS PASSED IN POINTS + SL_BY_PRICE=1, //STOP LOSS PASSED BY PRICE + }; + +//Enumerative for candle type +enum ENUM_CANDLE_TYPE + { + NEUTRAL_CANDLE=0, + BEARISH_CANDLE=1, + BULLISH_CANDLE=2, + }; + +//Enumerative for price momentum +enum ENUM_PRICE_MOMENTUM + { + UP=2, + DOWN=1, + NEUTRAL=0, + }; + +struct LastTransaction + { + string time; + int type; + double profit; + } lt; + +//-INPUT PARAMETERS-// +//The input parameters are the ones that can be set by the user when launching the EA +//If you place a comment following the input variable this will be shown as description of the field + +//This is where you should include the input parameters for your entry and exit signals +input string Comment_strategy="=========="; //Entry And Exit Settings +//Add in this section the parameters for the indicators used in your entry and exit + +//General input parameters +input string Comment_0="=========="; //Risk Management Settings +input ENUM_RISK_DEFAULT_SIZE RiskDefaultSize=RISK_DEFAULT_AUTO; //Position Size Mode +input double DefaultLotSize=1; //Position Size (if fixed or if no stop loss defined) +input ENUM_RISK_BASE RiskBase=RISK_BASE_BALANCE; //Risk Base +input double MaxRiskPerTrade=0.5; //Percentage To Risk Each Trade +input double MinLotSize=0.01; //Minimum Position Size Allowed +input double MaxLotSize=100; //Maximum Position Size Allowed + +input string Comment_1="=========="; //Trading Hours Settings +input bool UseTradingHours=false; //Limit Trading Hours +input string TradingHourStart="01"; //Trading Start Hour (Broker Server Hour) +input string TradingHourEnd="23"; //Trading End Hour (Broker Server Hour) +input string TradingStartMin="30"; //Trading Start minute (Broker Server Hour) +input string TradingEndMin="00"; //Trading End minute + +input string Comment_2="=========="; //Stop Loss And Take Profit Settings +input ENUM_MODE_SL StopLossMode=SL_AUTO; //Stop Loss Mode +input int DefaultStopLoss=0; //Default Stop Loss In Points (0=No Stop Loss) +input int MinStopLoss=0; //Minimum Allowed Stop Loss In Points +input int MaxStopLoss=5000; //Maximum Allowed Stop Loss In Points +input bool AtrStopLoss=false; //Set Stop loss based on ATR +input int atr_sl_factor=3; //Multiplicator for ATR stop loss +input ENUM_MODE_TP TakeProfitMode=TP_AUTO; //Take Profit Mode +input int DefaultTakeProfit=0; //Default Take Profit In Points (0=No Take Profit) +input int MinTakeProfit=0; //Minimum Allowed Take Profit In Points +input int MaxTakeProfit=5000; //Maximum Allowed Take Profit In Points +input double TakeProfitPercent=1.0; //Take Profit percent on risk base +input double Breakevent=1.0; //Minimum Profit to breakeven +input bool ProfitRun=true; +input bool ActiveMartingale=false; + +input string Comment_3="=========="; //Trailing Stop Settings +input bool UseTrailingStop=false; //Use Trailing Stop + +input string Comment_4="=========="; //Additional Settings +input int MagicNumber=0; //Magic Number For The Orders Opened By This EA +input string OrderNote=""; //Comment For The Orders Opened By This EA +input int Slippage=5; //Slippage in points +input double MaxSpread=10.0; //Maximum Allowed Spread To Trade In Points + +input string Comment_5="==========="; //Zigzag indicator setting +input int Depth=5; +input int Deviation=5; +input int Backstep=3; +input int GapPoint=100; //Minimum gap between peaks +input int Sensitivity=2; //Minimum peak at same level +input int LookBack=50; //Maximum peak to consider + +input int NumberOfCandles=3; + +//-GLOBAL VARIABLES-// +//The variables included in this section are global, hence they can be used in any part of the code +string Symb=Symbol(), server_time; + +long current_chart_id = ChartID(); + +bool IsPreChecksOk=false; //Indicates if the pre checks are satisfied +bool IsNewCandle=false; //Indicates if this is a new candle formed +bool IsSpreadOK=false; //Indicates if the spread is low enough to trade +bool IsOperatingHours=false; //Indicates if it is possible to trade at the current time (server time) +bool IsTradedThisBar=false; //Indicates if an order was already executed in the current candle +bool In_Trade = true; //Indicates if trade range has been formed +bool CanBuy = true; +bool CanSell = true; +bool ClosePosition = false; +bool FollowProfit = false; +bool UpTrendingMarket = false; +bool DownTrendingMarket = false; + +double TickValue=0; //Value of a tick in account currency at 1 lot +double LotSize=0; //Lot size for the position +double Tick_Size = SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_SIZE); //Tick size +double High[]; +double Low[]; +double PositionProfit; + +//Indicators + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +long Spread = SymbolInfoInteger(Symb,SYMBOL_SPREAD) / 100; //Check the impact. It's originally a double +int OrderOpRetry=10; //Number of attempts to retry the order submission +int TotalOpenOrders=0; //Number of total open orders +int TotalOpenBuy=0; //Number of total open buy orders +int TotalOpenSell=0; //Number of total open sell orders +int StopLossBy=SL_BY_POINTS; //How the stop loss is passed for the lot size calculation +double lotMultiplier =1; //Adust lot size according to loosing trades +int candleCounter =0; +double firstCandleOpen =0; +double lastCandleClose=0; +double ProfitRunTargetPercent=10.0; + +datetime LastBarTraded; + +MqlDateTime dt; +MqlTick last_tick; + +ENUM_SIGNAL_ENTRY SignalEntry=SIGNAL_ENTRY_NEUTRAL; //Entry signal variable +ENUM_SIGNAL_EXIT SignalExit=SIGNAL_EXIT_NEUTRAL; +ENUM_CANDLE_TYPE candleType=NEUTRAL_CANDLE; +ENUM_PRICE_MOMENTUM priceMomentum=NEUTRAL; +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/A_PositionsManager.mqh b/Include/Nkanven/A_PositionsManager.mqh new file mode 100644 index 0000000..ac8a2b1 --- /dev/null +++ b/Include/Nkanven/A_PositionsManager.mqh @@ -0,0 +1,123 @@ +//+------------------------------------------------------------------+ +//| A_PositionsManager.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; + +//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 +bool ScanPositions() + { + +//Scan all the orders, retrieving some of the details + TotalOpenOrders = 0; + TotalOpenBuy = 0; + TotalOpenSell = 0; + for(int i=0; iLastBarTraded || LastBarTraded==0) + LastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); + } + Print("Total positions ", TotalOpenOrders, " - Total buys ", TotalOpenBuy, " - Total sells ", TotalOpenSell); + return true; + } + +// We declare a function CloseOpenPositions of type int and we want to return +// the number of positions that are closed. +void CloseOpenPositions() + { + + int TotalClose=0; // We want to count how many orders have been closed. + int c_slippage = Slippage; + Print("Close position status ", ClosePosition); +// Normalization of the slippage. + if(_Digits==3 || _Digits==5) + { + c_slippage=c_slippage*10; + } + +// We scan all the orders backwards. +// This is required as if we start from the first order, we will have problems with the counters and the loop. + for(int i=PositionsTotal()-1; i>=0; i--) + { + + ulong ticket = PositionGetTicket(i); + + Print("Position profit is ", PositionGetDouble(POSITION_PROFIT)); + PositionProfit = PositionGetDouble(POSITION_PROFIT); + /*if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspana) + { + // We select the order of index i, selecting by position and from the pool of market/pending trades. + //If the selection is successful we try to close the order. + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + } + + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspana) + { + // We select the order of index i, selecting by position and from the pool of market/pending trades. + //If the selection is successful we try to close the order. + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + }*/ + + if(ClosePosition) + { + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + ClosePosition = false; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + } + // We can use a delay if the execution is too fast. + // Sleep() will wait X milliseconds before proceeding with the code. + // Sleep(300); + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/A_TradeManager.mqh b/Include/Nkanven/A_TradeManager.mqh new file mode 100644 index 0000000..fa829a9 --- /dev/null +++ b/Include/Nkanven/A_TradeManager.mqh @@ -0,0 +1,23 @@ +//+------------------------------------------------------------------+ +//| A_TradeManager.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +void ProfitRunner() + { + if(ProfitRun) + { + if(iClose(Symb, _Period, 1) < iClose(Symb, _Period, 2) && TotalOpenBuy > 0) + { + ClosePosition = true; + } + if(iClose(Symb, _Period, 1) > iClose(Symb, _Period, 2) && TotalOpenSell > 0) + { + ClosePosition = true; + } + } + Print("Looking to close this position ", ClosePosition); + } \ No newline at end of file diff --git a/Include/Nkanven/A_TradingHour.mqh b/Include/Nkanven/A_TradingHour.mqh new file mode 100644 index 0000000..72d352a --- /dev/null +++ b/Include/Nkanven/A_TradingHour.mqh @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| A_TradingHour.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/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..e69de29 diff --git a/Include/Nkanven/CandleCount/DCAManager.mqh b/Include/Nkanven/CandleCount/DCAManager.mqh new file mode 100644 index 0000000..908f40b --- /dev/null +++ b/Include/Nkanven/CandleCount/DCAManager.mqh @@ -0,0 +1,24 @@ +//+------------------------------------------------------------------+ +//| DCAManager.mqh | +//| Copyright 2022, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, MetaQuotes Ltd." +#property link "https://www.mql5.com" + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void DcaManager(string instrument) + { + +//Compute pending orders levels + + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void DcaWatcher(string intrument) {} +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/CandleCount/EntriesManager.mqh b/Include/Nkanven/CandleCount/EntriesManager.mqh new file mode 100644 index 0000000..4767f92 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; + } + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/DL_CheckHistory.mqh b/Include/Nkanven/DL_CheckHistory.mqh new file mode 100644 index 0000000..992b7ab Binary files /dev/null and b/Include/Nkanven/DL_CheckHistory.mqh differ diff --git a/Include/Nkanven/DL_CheckOperationHours.mqh b/Include/Nkanven/DL_CheckOperationHours.mqh new file mode 100644 index 0000000..e4f7362 --- /dev/null +++ b/Include/Nkanven/DL_CheckOperationHours.mqh @@ -0,0 +1,46 @@ +//+------------------------------------------------------------------+ +//| DL_CheckOperationHours.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +//Check and return if it is operation hours or not +void CheckOperationHours() + { +//If we are not using operating hours then IsOperatingHours is true and I skip the other checks + if(!UseTradingHours) + { + IsOperatingHours=true; + return; + } +//Check if the current hour is between the allowed hours of operations, if so IsOperatingHours is set true + Print("1 this is ", (TradingHourStart==TradingHourEnd && dt.hour==TradingHourStart && In_Trade)); + + if(TradingHourStart==TradingHourEnd && dt.hour==TradingHourStart && In_Trade) + IsOperatingHours=true; + + if(TradingHourStart= TradingStartMin) + { + IsOperatingHours=true; + } + if(dt.hour > TradingHourStart) + { + IsOperatingHours=true; + } + } + + if(TradingHourStart>TradingHourEnd && ((dt.hour>=TradingHourStart && dt.hour<=23) || (dt.hour<=TradingHourEnd && dt.hour>=0)) && In_Trade) + { + IsOperatingHours=true; + } + + if(IsOperatingHours == false) + { + rangeUpdated = false; + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/DL_ClosePositions.mqh b/Include/Nkanven/DL_ClosePositions.mqh new file mode 100644 index 0000000..b262b0f --- /dev/null +++ b/Include/Nkanven/DL_ClosePositions.mqh @@ -0,0 +1,67 @@ +//+------------------------------------------------------------------+ +//| DL_ClosePositions.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; + +// We declare a function CloseOpenPositions of type int and we want to return +// the number of positions that are closed. +void CloseOpenPositions() + { + + int TotalClose=0; // We want to count how many orders have been closed. + int c_slippage = Slippage; + +// Normalization of the slippage. + if(_Digits==3 || _Digits==5) + { + c_slippage=c_slippage*10; + } + + if(TimeToString(LastBarTraded, TIME_DATE) == TimeToString(TimeCurrent(), TIME_DATE)) + return; + +// We scan all the orders backwards. +// This is required as if we start from the first order, we will have problems with the counters and the loop. +// We select the order of index i, selecting by position and from the pool of market/pending trades. + + double accountProfit = AccountInfoDouble(ACCOUNT_EQUITY) - AccountInfoDouble(ACCOUNT_BALANCE); + double accountProfitPercent = (fabs(accountProfit)*100)/AccountInfoDouble(ACCOUNT_BALANCE); + if(accountProfit < 0 && accountProfitPercent >= 10) + { + + + + for(int i=PositionsTotal()-1; i>=0; i--) + { + + ulong ticket = PositionGetTicket(i); + + //If the selection is successful we try to close the order. + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + + /*Print("Position profit is ", PositionGetDouble(POSITION_PROFIT)); + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && PositionGetDouble(POSITION_PRICE_CURRENT) < upper_boundary || PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && PositionGetDouble(POSITION_PRICE_CURRENT) < upper_boundary) + { + + }*/ + + // We can use a delay if the execution is too fast. + // Sleep() will wait X milliseconds before proceeding with the code. + // Sleep(300); + } + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/DL_EntriesManagement.mqh b/Include/Nkanven/DL_EntriesManagement.mqh new file mode 100644 index 0000000..8cc157c Binary files /dev/null and b/Include/Nkanven/DL_EntriesManagement.mqh differ diff --git a/Include/Nkanven/DL_ErrorHandling.mqh b/Include/Nkanven/DL_ErrorHandling.mqh new file mode 100644 index 0000000..3684451 --- /dev/null +++ b/Include/Nkanven/DL_ErrorHandling.mqh @@ -0,0 +1,97 @@ +//+------------------------------------------------------------------+ +//| DL_ErrorHandling.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + + +//+------------------------------------------------------------------+ +//This functions returns a string corresponding to the description of an error +//Complete list of error available https://book.mql4.com/appendix/errors +string GetLastErrorText(int Error){ + string Text="Error Not Defined"; + if(Error==ERR_SUCCESS) Text="The operation completed successfully."; + if(Error==ERR_INTERNAL_ERROR) Text="Unexpected internal error."; + /*if(Error==ERR_COMMON_ERROR) Text="Common error."; + if(Error==ERR_INVALID_TRADE_PARAMETERS) Text="Invalid trade parameters."; + if(Error==ERR_SERVER_BUSY) Text="Trade server is busy."; + if(Error==ERR_OLD_VERSION) Text="Old version of the client terminal."; + if(Error==ERR_NO_CONNECTION) Text="No connection with trade server."; + if(Error==ERR_NOT_ENOUGH_RIGHTS) Text="Not enough rights."; + if(Error==ERR_TOO_FREQUENT_REQUESTS) Text="Too frequent requests."; + if(Error==ERR_MALFUNCTIONAL_TRADE) Text="Malfunctional trade operation."; + if(Error==ERR_ACCOUNT_DISABLED) Text="Account disabled."; + if(Error==ERR_INVALID_ACCOUNT) Text="Invalid account."; + if(Error==ERR_TRADE_TIMEOUT) Text="Trade timeout."; + if(Error==ERR_INVALID_PRICE) Text="Invalid price."; + if(Error==ERR_INVALID_STOPS) Text="Invalid stops."; + if(Error==ERR_INVALID_TRADE_VOLUME) Text="Invalid trade volume."; + if(Error==ERR_MARKET_CLOSED) Text="Market is closed."; + if(Error==ERR_TRADE_DISABLED) Text="Trade is disabled."; + if(Error==ERR_NOT_ENOUGH_MONEY) Text="Not enough money."; + if(Error==ERR_PRICE_CHANGED) Text="Price changed."; + if(Error==ERR_OFF_QUOTES) Text="Off quotes."; + if(Error==ERR_BROKER_BUSY) Text="Broker is busy."; + if(Error==ERR_REQUOTE) Text="Requote."; + if(Error==ERR_ORDER_LOCKED) Text="Order is locked."; + if(Error==ERR_LONG_POSITIONS_ONLY_ALLOWED) Text="Long positions only allowed."; + if(Error==ERR_TOO_MANY_REQUESTS) Text="Too many requests."; + if(Error==ERR_TRADE_MODIFY_DENIED) Text="Modification denied because an order is too close to market."; + if(Error==ERR_TRADE_CONTEXT_BUSY) Text="Trade context is busy."; + if(Error==ERR_TRADE_EXPIRATION_DENIED) Text="Expirations are denied by broker."; + if(Error==ERR_TRADE_TOO_MANY_ORDERS) Text="The amount of opened and pending orders has reached the limit set by a broker."; + if(Error==ERR_NO_MQLERROR) Text="No error."; + if(Error==ERR_WRONG_FUNCTION_POINTER) Text="Wrong function pointer."; + if(Error==ERR_ARRAY_INDEX_OUT_OF_RANGE) Text="Array index is out of range."; + if(Error==ERR_RECURSIVE_STACK_OVERFLOW) Text="Recursive stack overflow."; + if(Error==ERR_NO_MEMORY_FOR_TEMP_STRING) Text="No memory for temp string."; + if(Error==ERR_NOT_INITIALIZED_STRING) Text="Not initialized string."; + if(Error==ERR_NOT_INITIALIZED_ARRAYSTRING) Text="Not initialized string in an array."; + if(Error==ERR_NO_MEMORY_FOR_ARRAYSTRING) Text="No memory for an array string."; + if(Error==ERR_TOO_LONG_STRING) Text="Too long string."; + if(Error==ERR_REMAINDER_FROM_ZERO_DIVIDE) Text="Remainder from zero divide."; + if(Error==ERR_ZERO_DIVIDE) Text="Zero divide."; + if(Error==ERR_UNKNOWN_COMMAND) Text="Unknown command."; + if(Error==ERR_WRONG_JUMP) Text="Wrong jump."; + if(Error==ERR_NOT_INITIALIZED_ARRAY) Text="Not initialized array."; + if(Error==ERR_DLL_CALLS_NOT_ALLOWED) Text="DLL calls are not allowed."; + if(Error==ERR_CANNOT_LOAD_LIBRARY) Text="Cannot load library."; + if(Error==ERR_CANNOT_CALL_FUNCTION) Text="Cannot call function."; + if(Error==ERR_SYSTEM_BUSY) Text="System is busy."; + if(Error==ERR_SOME_ARRAY_ERROR) Text="Some array error."; + if(Error==ERR_CUSTOM_INDICATOR_ERROR) Text="Custom indicator error."; + if(Error==ERR_INCOMPATIBLE_ARRAYS) Text="Arrays are incompatible."; + if(Error==ERR_GLOBAL_VARIABLE_NOT_FOUND) Text="Global variable not found."; + if(Error==ERR_FUNCTION_NOT_CONFIRMED) Text="Function is not confirmed."; + if(Error==ERR_SEND_MAIL_ERROR) Text="Mail sending error."; + if(Error==ERR_STRING_PARAMETER_EXPECTED) Text="String parameter expected."; + if(Error==ERR_INTEGER_PARAMETER_EXPECTED) Text="Integer parameter expected."; + if(Error==ERR_DOUBLE_PARAMETER_EXPECTED) Text="Double parameter expected."; + if(Error==ERR_ARRAY_AS_PARAMETER_EXPECTED) Text="Array as parameter expected."; + if(Error==ERR_HISTORY_WILL_UPDATED) Text="Requested history data in updating state."; + if(Error==ERR_TRADE_ERROR) Text="Some error in trade operation execution."; + if(Error==ERR_END_OF_FILE) Text="End of a file."; + if(Error==ERR_SOME_FILE_ERROR) Text="Some file error."; + if(Error==ERR_WRONG_FILE_NAME) Text="Wrong file name."; + if(Error==ERR_TOO_MANY_OPENED_FILES) Text="Too many opened files."; + if(Error==ERR_CANNOT_OPEN_FILE) Text="Cannot open file."; + if(Error==ERR_NO_ORDER_SELECTED) Text="No order selected."; + if(Error==ERR_UNKNOWN_SYMBOL) Text="Unknown symbol."; + if(Error==ERR_INVALID_PRICE_PARAM) Text="Invalid price."; + if(Error==ERR_INVALID_TICKET) Text="Invalid ticket."; + if(Error==ERR_TRADE_NOT_ALLOWED) Text="Trade is not allowed."; + if(Error==ERR_LONGS_NOT_ALLOWED) Text="Longs are not allowed."; + if(Error==ERR_SHORTS_NOT_ALLOWED) Text="Shorts are not allowed."; + if(Error==ERR_OBJECT_ALREADY_EXISTS) Text="Object already exists."; + if(Error==ERR_UNKNOWN_OBJECT_PROPERTY) Text="Unknown object property."; + if(Error==ERR_OBJECT_DOES_NOT_EXIST) Text="Object does not exist."; + if(Error==ERR_UNKNOWN_OBJECT_TYPE) Text="Unknown object type."; + if(Error==ERR_NO_OBJECT_NAME) Text="No object name."; + if(Error==ERR_OBJECT_COORDINATES_ERROR) Text="Object coordinates error."; + if(Error==ERR_NO_SPECIFIED_SUBWINDOW) Text="No specified subwindow."; + if(Error==ERR_SOME_OBJECT_ERROR) Text="Some error in object operation.";*/ + + return Text; +} \ No newline at end of file diff --git a/Include/Nkanven/DL_InitMQL4.mqh b/Include/Nkanven/DL_InitMQL4.mqh new file mode 100644 index 0000000..b65eeca --- /dev/null +++ b/Include/Nkanven/DL_InitMQL4.mqh @@ -0,0 +1,65 @@ +//+------------------------------------------------------------------+ +//| InitMQL4.mqh | +//| Copyright DC2008 | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "keiji" +#property copyright "DC2008" +#property link "https://www.mql5.com" +//--- Declaration of constants +#define OP_BUY 0 //Buy +#define OP_SELL 1 //Sell +#define OP_BUYLIMIT 2 //Pending order of BUY LIMIT type +#define OP_SELLLIMIT 3 //Pending order of SELL LIMIT type +#define OP_BUYSTOP 4 //Pending order of BUY STOP type +#define OP_SELLSTOP 5 //Pending order of SELL STOP type +//--- +#define MODE_OPEN 0 +#define MODE_CLOSE 3 +#define MODE_VOLUME 4 +#define MODE_REAL_VOLUME 5 +#define MODE_TRADES 0 +#define MODE_HISTORY 1 +#define SELECT_BY_POS 0 +#define SELECT_BY_TICKET 1 +//--- +#define DOUBLE_VALUE 0 +#define FLOAT_VALUE 1 +#define LONG_VALUE INT_VALUE +//--- +#define CHART_BAR 0 +#define CHART_CANDLE 1 +//--- +#define MODE_ASCEND 0 +#define MODE_DESCEND 1 +//--- +#define MODE_LOW 1 +#define MODE_HIGH 2 +#define MODE_TIME 5 +#define MODE_BID 9 +#define MODE_ASK 10 +#define MODE_POINT 11 +#define MODE_DIGITS 12 +#define MODE_SPREAD 13 +#define MODE_STOPLEVEL 14 +#define MODE_LOTSIZE 15 +#define MODE_TICKVALUE 16 +#define MODE_TICKSIZE 17 +#define MODE_SWAPLONG 18 +#define MODE_SWAPSHORT 19 +#define MODE_STARTING 20 +#define MODE_EXPIRATION 21 +#define MODE_TRADEALLOWED 22 +#define MODE_MINLOT 23 +#define MODE_LOTSTEP 24 +#define MODE_MAXLOT 25 +#define MODE_SWAPTYPE 26 +#define MODE_PROFITCALCMODE 27 +#define MODE_MARGINCALCMODE 28 +#define MODE_MARGININIT 29 +#define MODE_MARGINMAINTENANCE 30 +#define MODE_MARGINHEDGED 31 +#define MODE_MARGINREQUIRED 32 +#define MODE_FREEZELEVEL 33 +//--- +#define EMPTY -1 \ No newline at end of file diff --git a/Include/Nkanven/DL_LotSizeCal.mqh b/Include/Nkanven/DL_LotSizeCal.mqh new file mode 100644 index 0000000..02a99d1 --- /dev/null +++ b/Include/Nkanven/DL_LotSizeCal.mqh @@ -0,0 +1,54 @@ +//+------------------------------------------------------------------+ +//| DL_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(RiskDefaultSize==RISK_DEFAULT_AUTO) + { + //If the stop loss is not zero then calculate the lot size + if(SL!=0) + { + double RiskBaseAmount=0; + //TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty + TickValue=SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_VALUE); + //Define the base for the risk calculation depending on the parameter chosen + if(RiskBase==RISK_BASE_BALANCE) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE); + if(RiskBase==RISK_BASE_EQUITY) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY); + if(RiskBase==RISK_BASE_FREEMARGIN) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN); + + //Calculate the Position Size + LotSize=((RiskBaseAmount*MaxRiskPerTrade/100)/(SL*TickValue)); + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=DefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>MaxLotSize) + LotSize=MaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX); + Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSizeMaxStopLoss) + { + IsPreChecksOk=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(DefaultTakeProfitMaxTakeProfit) + { + IsPreChecksOk=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(DefaultLotSizeMaxLotSize) + { + IsPreChecksOk=false; + Print("Default Lot Size must be between Minimum and Maximum Lot Size Allowed"); + return; + } +//Slippage must be >= 0 + if(Slippage<0) + { + IsPreChecksOk=false; + Print("Slippage must be a positive value"); + return; + } +//MaxSpread must be >= 0 + if(MaxSpread<0) + { + IsPreChecksOk=false; + Print("Maximum Spread must be a positive value"); + return; + } +//MaxRiskPerTrade is a % between 0 and 100 + if(MaxRiskPerTrade<0 || MaxRiskPerTrade>100) + { + IsPreChecksOk=false; + Print("Maximum Risk Per Trade must be a percentage between 0 and 100"); + return; + } + } diff --git a/Include/Nkanven/DL_ScanPositions.mqh b/Include/Nkanven/DL_ScanPositions.mqh new file mode 100644 index 0000000..4cb5d70 --- /dev/null +++ b/Include/Nkanven/DL_ScanPositions.mqh @@ -0,0 +1,49 @@ +//+------------------------------------------------------------------+ +//| DL_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 +bool ScanPositions() + { + +//Scan all the orders, retrieving some of the details + TotalOpenOrders = 0; + TotalOpenBuy = 0; + TotalOpenSell = 0; + for(int i=0; iLastBarTraded || LastBarTraded==0) + LastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); + } + Print("Total positions ", TotalOpenOrders, " - Total buys ", TotalOpenBuy, " - Total sells ", TotalOpenSell); + return true; + } \ No newline at end of file diff --git a/Include/Nkanven/DL_TradeManagement.mqh b/Include/Nkanven/DL_TradeManagement.mqh new file mode 100644 index 0000000..99524ff --- /dev/null +++ b/Include/Nkanven/DL_TradeManagement.mqh @@ -0,0 +1,20 @@ +//+------------------------------------------------------------------+ +//| DL_TradeManagement.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +bool ShouldTrade() + { + //double minProfitAllow = ((AccountInfoDouble(ACCOUNT_BALANCE)*MaxRiskPerTrade)/100)*(TakeProfitPercent*MinStopTradeProfit); +Print("1 Profit ", lt.profit, " Hist time ", lt.time, " current time ", TimeToString(TimeCurrent(), TIME_DATE)); + if(lt.time == TimeToString(TimeCurrent(), TIME_DATE) && lt.profit > 0) + { + Print("2 Profit ", lt.profit); + return false; + } + return true; + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/DL_TradingBoundaries.mqh b/Include/Nkanven/DL_TradingBoundaries.mqh new file mode 100644 index 0000000..d3b231b --- /dev/null +++ b/Include/Nkanven/DL_TradingBoundaries.mqh @@ -0,0 +1,112 @@ +//+------------------------------------------------------------------+ +//| DL_TradingBoundaries.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +double newHigh, newLow; +bool rangeUpdated = false; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void drawRange() + { + string candles_times; + int time_to_string; + ushort a; + string d_time = TimeToString(iTime(Symb,PERIOD_M5,0), TIME_MINUTES); + string open_hour[]; + string obj_name = "Upper boundary", obj_name_l = "Lower boundary"; + + ArraySetAsSeries(High,true); + CopyHigh(_Symbol,_Period,0,MaxCandleIteration,High); + + ArraySetAsSeries(Low,true); + CopyLow(_Symbol,_Period,0,MaxCandleIteration,Low); + +//--- Get the separator code + a = StringGetCharacter(":",0); + + int k = StringSplit(d_time, a, open_hour); + + if(k>0) + { + server_time = "Server time on last 5 Min candle => Hour = " +open_hour[0]+ ", Minute = " +open_hour[1]; + } + +// Get trading range + for(int j = 0; j <= MaxCandleIteration; j++) + { + string result[]; + candles_times = TimeToString(iTime(Symb,_Period,j), TIME_MINUTES); + time_to_string = StringSplit(candles_times, a, result); + //Print("Is trading boundary "+(result[0] == TradingBoundaryHour && result[1] == TradingBoundaryMin)); + if(result[0] == TradingBoundaryHour && result[1] == TradingBoundaryMin) + { + if(!rangeUpdated) + { + upper_boundary = iHigh(Symb, _Period, j) + rangemargin; + lower_boundary = iLow(Symb, _Period, j)- rangemargin; + } + + UpdateRange(); + //Print("Iteration no "+iTime(Symb,PERIOD_M5,j)); + ObjectCreate(current_chart_id, obj_name, OBJ_HLINE, 0, iTime(Symb,_Period,j), upper_boundary); + + //--- set color to Red + ObjectSetInteger(current_chart_id, obj_name, OBJPROP_COLOR, clrRed); + //--- set object width + ObjectSetInteger(current_chart_id, obj_name, OBJPROP_WIDTH, 2); + //--- Move the line + ObjectMove(current_chart_id, obj_name, 0, iTime(Symb,_Period,j), upper_boundary); + + ObjectCreate(current_chart_id, obj_name_l, OBJ_HLINE, 0, iTime(Symb,_Period,j), lower_boundary); + + //--- set color to Red + ObjectSetInteger(current_chart_id, obj_name_l, OBJPROP_COLOR, clrRed); + //--- set object width + ObjectSetInteger(current_chart_id, obj_name_l, OBJPROP_WIDTH, 2); + //--- Move the line + ObjectMove(current_chart_id, obj_name_l, 0, iTime(Symb,_Period,j), lower_boundary); + + if(!rangedetection) + { + upper_boundary = upperboundary; + lower_boundary = lowerboundary; + } + + //Print("upper_boundary ", upper_boundary, " lower_boundary ", lower_boundary); + //Print("Real high ", iHigh(Symb, PERIOD_M5, j), " Real low ", iLow(Symb, PERIOD_M5, j), " as of ", TimeToString(iTime(Symb,PERIOD_M5, j))); + In_Trade = true; + rangeScope = fabs(upper_boundary-lower_boundary); + break; + } + ObjectDelete(current_chart_id, obj_name_l); + ObjectDelete(current_chart_id, obj_name); + In_Trade = false; + } + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void UpdateRange() + { + newHigh = iHigh(Symb, PERIOD_CURRENT, 0); + newLow = iLow(Symb, PERIOD_CURRENT, 0); + Print("Updating range high from ", upper_boundary, "to ", newHigh, " and low from ", lower_boundary, " to ", newLow); + if(newHigh > upper_boundary && TotalOpenBuy > 0) + { + upper_boundary = newHigh; + rangeUpdated = true; + } + if(lower_boundary > newLow && TotalOpenSell > 0) + { + lower_boundary = newLow; + rangeUpdated = true; + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/E_CheckHistory.mqh b/Include/Nkanven/E_CheckHistory.mqh new file mode 100644 index 0000000..aa967ff Binary files /dev/null and b/Include/Nkanven/E_CheckHistory.mqh differ diff --git a/Include/Nkanven/E_ClosePositions.mqh b/Include/Nkanven/E_ClosePositions.mqh new file mode 100644 index 0000000..7b061e4 --- /dev/null +++ b/Include/Nkanven/E_ClosePositions.mqh @@ -0,0 +1,81 @@ +//+------------------------------------------------------------------+ +//| E_ClosePositions.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; + +// We declare a function CloseOpenPositions of type int and we want to return +// the number of positions that are closed. +void CloseOpenPositions() + { + + int TotalClose=0; // We want to count how many orders have been closed. + int c_slippage = Slippage; +Print("Close position status ", ClosePosition); +// Normalization of the slippage. + if(_Digits==3 || _Digits==5) + { + c_slippage=c_slippage*10; + } + +// We scan all the orders backwards. +// This is required as if we start from the first order, we will have problems with the counters and the loop. + for(int i=PositionsTotal()-1; i>=0; i--) + { + + ulong ticket = PositionGetTicket(i); + + Print("Position profit is ", PositionGetDouble(POSITION_PROFIT)); + PositionProfit = PositionGetDouble(POSITION_PROFIT); + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspana) + { + // We select the order of index i, selecting by position and from the pool of market/pending trades. + //If the selection is successful we try to close the order. + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + } + + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspana) + { + // We select the order of index i, selecting by position and from the pool of market/pending trades. + //If the selection is successful we try to close the order. + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + } + + if(ClosePosition) + { + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + ClosePosition = false; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + } + // We can use a delay if the execution is too fast. + // Sleep() will wait X milliseconds before proceeding with the code. + // Sleep(300); + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/E_EntriesManagement.mqh b/Include/Nkanven/E_EntriesManagement.mqh new file mode 100644 index 0000000..e202f27 Binary files /dev/null and b/Include/Nkanven/E_EntriesManagement.mqh differ diff --git a/Include/Nkanven/E_Parameters.mqh b/Include/Nkanven/E_Parameters.mqh new file mode 100644 index 0000000..d7ff205 Binary files /dev/null and b/Include/Nkanven/E_Parameters.mqh differ diff --git a/Include/Nkanven/E_ScanPositions.mqh b/Include/Nkanven/E_ScanPositions.mqh new file mode 100644 index 0000000..53f5789 --- /dev/null +++ b/Include/Nkanven/E_ScanPositions.mqh @@ -0,0 +1,49 @@ +//+------------------------------------------------------------------+ +//| E_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 +bool ScanPositions() + { + +//Scan all the orders, retrieving some of the details + TotalOpenOrders = 0; + TotalOpenBuy = 0; + TotalOpenSell = 0; + for(int i=0; iLastBarTraded || LastBarTraded==0) + LastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); + } + Print("Total positions ", TotalOpenOrders, " - Total buys ", TotalOpenBuy, " - Total sells ", TotalOpenSell); + return true; + } \ No newline at end of file diff --git a/Include/Nkanven/E_TradeManagement.mqh b/Include/Nkanven/E_TradeManagement.mqh new file mode 100644 index 0000000..9b95978 --- /dev/null +++ b/Include/Nkanven/E_TradeManagement.mqh @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| E_TradeManagement.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +//Done for the day after a profitable trade +//If closed trade was opened the day before, look for trade opportunities +double minProfitAllow = AccountInfoDouble(ACCOUNT_BALANCE)*(Breakevent/100); +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void TradeManager() + { + CanSell = true; + CanBuy = true; + + if(lt.time == TimeToString(TimeCurrent(), TIME_DATE)) + { + if(lt.type == DEAL_TYPE_BUY && lt.profit < 0) + { + CanBuy = false; + } + if(lt.type = DEAL_TYPE_SELL && lt.profit < 0) + { + CanSell = false; + } + } + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ProfitRunner() + { + Print("Min acceptablbe profit ", minProfitAllow); + ClosePosition = false; + if(PositionProfit > minProfitAllow) + FollowProfit=true; + + if(FollowProfit) + { + if(Kijunsen > iClose(Symb, _Period, 1) && TotalOpenBuy > 0) + { + ClosePosition = true; + } + if(Kijunsen < iClose(Symb, _Period, 1) && TotalOpenSell > 0) + { + ClosePosition = true; + } + } + Print("Looking to close this position ", ClosePosition, " Follow profit ", FollowProfit); + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/ExpertBase.mqh b/Include/Nkanven/ExpertBase.mqh new file mode 100644 index 0000000..e5afc1d --- /dev/null +++ b/Include/Nkanven/ExpertBase.mqh @@ -0,0 +1,380 @@ +/* + ExpertBase.mqh + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + +*/ + + +#include "CommonBase.mqh" +#include "SignalBase.mqh" +#include "TPSLBase.mqh" +#include "Trade/Trade.mqh" + +class CExpertBase : public CCommonBase { + +protected: + + int mMagicNumber; + string mTradeComment; + + double mVolume; + + datetime mLastBarTime; + datetime mBarTime; + + ////Changed + // Arrays to hold the signal objects + CSignalBase *mEntrySignals[]; + CSignalBase *mExitSignals[]; + ////CSignalBase *mEntrySignal; + ////CSignalBase *mExitSignal; + + double mTakeProfitValue; + double mStopLossValue; + CTPSLBase *mTakeProfitObj; + CTPSLBase *mStopLossObj; + + CTradeCustom Trade; + +private: + +protected: + + virtual bool LoopMain(bool newBar, bool firstTime); + +protected: + + int Init(int magicNumber, string tradeComment); + +public: + + // + // Constructors + // + CExpertBase() : CCommonBase() + { Init(0, ""); } + CExpertBase(string symbol, int timeframe, int magicNumber, string tradeComment) + : CCommonBase(symbol, timeframe) + { Init(magicNumber, tradeComment); } + CExpertBase(string symbol, ENUM_TIMEFRAMES timeframe, int magicNumber, string tradeComment) + : CCommonBase(symbol, timeframe) + { Init(magicNumber, tradeComment); } + CExpertBase(int magicNumber, string tradeComment) + : CCommonBase() + { Init(magicNumber, tradeComment); } + + // + // Destructors + // + ~CExpertBase(); + +public: // Default properties + + // + // Assign the default values to the expert + // + virtual void SetVolume(double volume) { mVolume = volume; } + + virtual void SetTakeProfitValue(int takeProfitPoints) + { mTakeProfitValue = PointsToDouble(takeProfitPoints); } + virtual void SetTakeProfitObj(CTPSLBase *takeProfitObj) + { mTakeProfitObj = takeProfitObj; } + + virtual void SetStopLossValue(int stopLossPoints) + { mStopLossValue = PointsToDouble(stopLossPoints); } + virtual void SetStopLossObj(CTPSLBase *stopLossObj) + { mStopLossObj = stopLossObj; } + + virtual void SetTradeComment(string comment) { mTradeComment = comment; } + virtual void SetMagic(int magicNumber) { mMagicNumber = magicNumber; + Trade.SetExpertMagicNumber(magicNumber); } + +public: // Setup + + ////Changed + virtual void AddEntrySignal(CSignalBase *signal) { AddSignal(signal, mEntrySignals); } + virtual void AddExitSignal(CSignalBase *signal) { AddSignal(signal, mExitSignals); } + virtual void AddSignal(CSignalBase *signal, CSignalBase* &signals[]); + ////virtual void AddEntrySignal(CSignalBase *signal) { mEntrySignal=signal; } + ////virtual void AddExitSignal(CSignalBase *signal) { mExitSignal=signal; } + +public: // Event handlers + + virtual int OnInit(); + virtual void OnTick(); + virtual void OnTimer() { return; } + virtual double OnTester() { return(0.0); } + virtual void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {}; + +#ifdef __MQL5__ + virtual void OnTrade() { return; } + virtual void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { return; } + virtual int OnTesterInit() { return(INIT_SUCCEEDED); } + virtual void OnTesterPass() { return; } + virtual void OnTesterDeinit() { return; } + virtual void OnBookEvent() { return; } +#endif + +public: // Functions + + virtual void GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request); + ////New + virtual ENUM_OFX_SIGNAL_DIRECTION GetCurrentSignal(CSignalBase* &signals[], + ENUM_OFX_SIGNAL_TYPE signalType); + +}; + +CExpertBase::~CExpertBase() { + +} + +int CExpertBase::OnInit() { + + int i = 0; + for (i=ArraySize(mEntrySignals)-1; i>=0; i--) { + if (mEntrySignals[i].InitResult()!=INIT_SUCCEEDED) return(mEntrySignals[i].InitResult()); + } + for (i=ArraySize(mExitSignals)-1; i>=0; i--) { + if (mExitSignals[i].InitResult()!=INIT_SUCCEEDED) return(mExitSignals[i].InitResult()); + } + if (mTakeProfitObj!=NULL) { + if (mTakeProfitObj.InitResult()!=INIT_SUCCEEDED) return(mTakeProfitObj.InitResult()); + } + if (mStopLossObj!=NULL) { + if (mStopLossObj.InitResult()!=INIT_SUCCEEDED) return(mStopLossObj.InitResult()); + } + + return(INIT_SUCCEEDED); + +} + +int CExpertBase::Init(int magicNumber, string tradeComment) { + + if (mInitResult!=INIT_SUCCEEDED) return(mInitResult); + + mTradeComment = tradeComment; + SetMagic(magicNumber); + + mTakeProfitValue = 0.0; + mStopLossValue = 0.0; + + mLastBarTime = 0; + + ////New + ArrayResize(mEntrySignals, 0); // Just make sure these are initialised + ArrayResize(mExitSignals, 0); + + return(INIT_SUCCEEDED); + +} + +void CExpertBase::OnTick(void) { + + if (!TradeAllowed()) return; + + mBarTime = iTime(mSymbol, mTimeframe, 0); + + bool firstTime = (mLastBarTime==0); + bool newBar = (mBarTime!=mLastBarTime); + + if (LoopMain(newBar, firstTime)) { + mLastBarTime = mBarTime; + } + + return; + +} + +bool CExpertBase::LoopMain(bool newBar,bool firstTime) { + + // + // To start I will only trade on a new bar + // and not on the first bar after start + // + if (!newBar) return(true); + if (firstTime) return(true); + + // + // Update the signals + // + ////Changed + ENUM_OFX_SIGNAL_DIRECTION entrySignal = GetCurrentSignal(mEntrySignals, OFX_ENTRY_SIGNAL); + ENUM_OFX_SIGNAL_DIRECTION exitSignal = GetCurrentSignal(mExitSignals, OFX_EXIT_SIGNAL); + ////if (mEntrySignal!=NULL) mEntrySignal.UpdateSignal(); + ////if (mEntrySignal!=mExitSignal) { + //// if (mExitSignal!=NULL) mExitSignal.UpdateSignal(); + ////} + + // + // Should any trades be closed + // + ////Changed + if (exitSignal==OFX_SIGNAL_BOTH) { + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + } else + if (exitSignal==OFX_SIGNAL_BUY) { + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + } else + if (exitSignal==OFX_SIGNAL_SELL) { + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + } + ////if (mExitSignal!=NULL) { + //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BOTH) { + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + //// } else + //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BUY) { + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + //// } else + //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_SELL) { + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + //// } + ////} + + // + // Should a trade be opened + // + MqlTradeRequest request = {}; // Just initialising + ////Changed + if (entrySignal==OFX_SIGNAL_BOTH) { + + GetMarketPrices(ORDER_TYPE_BUY, request); + Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); + + GetMarketPrices(ORDER_TYPE_SELL, request); + Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); + + } else + if (entrySignal==OFX_SIGNAL_BUY) { + + GetMarketPrices(ORDER_TYPE_BUY, request); + Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); + + } else + if (entrySignal==OFX_SIGNAL_SELL) { + + GetMarketPrices(ORDER_TYPE_SELL, request); + Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); + + } +//// if (mEntrySignal!=NULL) { +//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BOTH) { +//// +//// GetMarketPrices(ORDER_TYPE_BUY, request); +//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// GetMarketPrices(ORDER_TYPE_SELL, request); +//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// } else +//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BUY) { +//// +//// GetMarketPrices(ORDER_TYPE_BUY, request); +//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// } else +//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_SELL) { +//// +//// GetMarketPrices(ORDER_TYPE_SELL, request); +//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// } +//// } + + return(true); + +} + +void CExpertBase::GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request) { + + double sl = (mStopLossObj==NULL) ? mStopLossValue : mStopLossObj.GetStopLoss(); + double tp = (mTakeProfitObj==NULL) ? mTakeProfitValue : mTakeProfitObj.GetTakeProfit(); + + if (orderType==ORDER_TYPE_BUY) { + if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_ASK); + request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price+tp, mDigits); + request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price-sl, mDigits); + } + + if (orderType==ORDER_TYPE_SELL) { + if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_BID); + request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits); + request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits); + } + + return; + +} + +////New +void CExpertBase::AddSignal(CSignalBase *signal, CSignalBase* &signals[]) { + + int index = ArraySize(signals); + ArrayResize(signals, index+1); + signals[index] = signal; + +} + +////New +ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalBase* &signals[], + ENUM_OFX_SIGNAL_TYPE signalType) { + + ENUM_OFX_SIGNAL_DIRECTION result = OFX_SIGNAL_NONE; + ENUM_OFX_SIGNAL_DIRECTION r2 = OFX_SIGNAL_NONE; // Just working value + int index = ArraySize(signals); + + if (index<=0) { + + return(result); + + } else { + + signals[0].UpdateSignal(); + result = signals[0].GetSignal(signalType); + + // I have chosen to update all signals in case there is some + // behavour that needs it. The penalty is some performance + // If performance is an issue just add an exit inside the loop + // as the commented line + for (int i = 1; i0) value = bufferData[0]; -#endif - - return(value); - -} - - diff --git a/Include/Nkanven/Frameworks/Extensions/Indicators/IndicatorMA.mqh b/Include/Nkanven/Frameworks/Extensions/Indicators/IndicatorMA.mqh deleted file mode 100644 index 7391f4a..0000000 --- a/Include/Nkanven/Frameworks/Extensions/Indicators/IndicatorMA.mqh +++ /dev/null @@ -1,82 +0,0 @@ -/* - IndicatorMA.mqh - Updated - requires version 2.01 or later - - Copyright 2013-2020, Orchard Forex - https://www.orchardforex.com - -*/ - -#include "../../Framework.mqh" - -class CIndicatorMA : public CIndicatorBase { - -private: - -protected: // member variables - - int mPeriods; - int mShift; - ENUM_MA_METHOD mMethod; - ENUM_APPLIED_PRICE mAppliedPrice; - -public: // constructors - - CIndicatorMA(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice) - : CIndicatorBase() - { Init(periods, shift, method, appliedPrice); } - CIndicatorMA(string symbol, ENUM_TIMEFRAMES timeframe, - int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice) - : CIndicatorBase(symbol, timeframe) - { Init(periods, shift, method, appliedPrice); } - ~CIndicatorMA(); - - virtual int Init(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice); - -public: - - virtual double GetData(const int buffer_num,const int index); - -}; - -CIndicatorMA::~CIndicatorMA() { - -} - -int CIndicatorMA::Init(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice) { - - if (InitResult()!=INIT_SUCCEEDED) return(InitResult()); - - mPeriods = periods; - mShift = shift; - mMethod = method; - mAppliedPrice = appliedPrice; - -#ifdef __MQL5__ - mIndicatorHandle = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice); - if (mIndicatorHandle==INVALID_HANDLE) return(InitError("Failed to create indicator handle", INIT_FAILED)); -#endif - - return(INIT_SUCCEEDED); - -} - -double CIndicatorMA::GetData(const int buffer_num,const int index) { - - double value = 0; -#ifdef __MQL4__ - value = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice, index); -#endif - -#ifdef __MQL5__ - double bufferData[]; - ArraySetAsSeries(bufferData, true); - int cnt = CopyBuffer(mIndicatorHandle, buffer_num, index, 1, bufferData); - if (cnt>0) value = bufferData[0]; -#endif - - return(value); - -} - - diff --git a/Include/Nkanven/Frameworks/Extensions/Indicators/IndicatorTemplate.mqh b/Include/Nkanven/Frameworks/Extensions/Indicators/IndicatorTemplate.mqh deleted file mode 100644 index 898f7e1..0000000 --- a/Include/Nkanven/Frameworks/Extensions/Indicators/IndicatorTemplate.mqh +++ /dev/null @@ -1,91 +0,0 @@ -/* - IndicatorTemplate.mqh - Updated as of framework version 2.02 - - Copyright 2013-2020, Orchard Forex - https://www.orchardforex.com - -*/ - -// Next line assumes this file is located in .../Frameworks/Extensions/someFolder -#include "../../Framework.mqh" - -class CIndicatorTemplate : public CIndicatorBase { - -private: - -protected: // member variables - -// Place any required member variables here - -public: // constructors - - // Add any required constructor arguments - // e.g. CIndicatorXYZ(int periods, double multiplier) - CIndicatorTemplate() - : CIndicatorBase() - { Init(); } - // Same constructor with symbol and timeframe added - CIndicatorTemplate(string symbol, ENUM_TIMEFRAMES timeframe) - : CIndicatorBase(symbol, timeframe) - { Init(); } - ~CIndicatorTemplate(); - - // Include all arguments to match the constructor - virtual int Init(); - -public: - - // Add this line to override the same function from the parent class - virtual double GetData(const int buffer_num,const int index); - -}; - -CIndicatorTemplate::~CIndicatorTemplate() { - - // Any destructors here - -} - -int CIndicatorTemplate::Init() { - - // Checks if init has been set to fail by any parent class already - if (InitResult()!=INIT_SUCCEEDED) return(InitResult()); - - // Assign variables and do any other initialisation here - -#ifdef __MQL5__ - // Just using iMA as an example here, replace as necessary -// mIndicatorHandle = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice); -// if (mIndicatorHandle==INVALID_HANDLE) return(InitError("Failed to create indicator handle", INIT_FAILED)); -#endif - - return(INIT_SUCCEEDED); - -} - -double CIndicatorTemplate::GetData(const int buffer_num,const int index) { - - double value = 0; -#ifdef __MQL4__ - // Next line is just an example using iMA - // value = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice, index); -#endif - -#ifdef __MQL5__ - // For MQL5 once indicator handle is set the code here should be common - // Declare a buffer to hold the data being retrieved - double bufferData[]; - // Set as series so the sequence matches the chrt - ArraySetAsSeries(bufferData, true); - // Copy indicator data into the buffer and get the count of elements - int cnt = CopyBuffer(mIndicatorHandle, buffer_num, index, 1, bufferData); - // If not enough elements came back then don't use the data - if (cnt>0) value = bufferData[0]; -#endif - - return(value); - -} - - diff --git a/Include/Nkanven/Frameworks/Extensions/Signals/SignalGrid.mqh b/Include/Nkanven/Frameworks/Extensions/Signals/SignalGrid.mqh index 15046a9..c923fd1 100644 --- a/Include/Nkanven/Frameworks/Extensions/Signals/SignalGrid.mqh +++ b/Include/Nkanven/Frameworks/Extensions/Signals/SignalGrid.mqh @@ -20,6 +20,10 @@ protected: // member variables // Place any required member variables here int m_magic; + double lastBuyOrderPrice; + double lastSellOrderPrice; + double openedBuyPositionPrice; + double openedSellPositionPrice; public: // constructors @@ -44,6 +48,10 @@ public: virtual void setMmagic(int magic) {m_magic = magic;} + virtual double getLastBuyOrderPrice() {return lastBuyOrderPrice;} + virtual double getLastSellOrderPrice() {return lastSellOrderPrice;} + virtual double getOpenedBuyPositionPrice() {return openedBuyPositionPrice;} + virtual double getOpenedSellPositionPrice() {return openedSellPositionPrice;} }; //+------------------------------------------------------------------+ @@ -73,7 +81,129 @@ void CSignalGrid::UpdateSignal() // This is the trade decision logic //CSignalBase signal = new CSignalBase(); +// Check the account balance equity for profit + int pCountBuy = 0, pCountSell = 0, oCountBuy = 0, oCountSell = 0, totalBuy = 0, totalSell = 0, realTotalBuy = 0, realTotalSell = 0; + int realOCountBuy = 0, realOCountSell = 0; + ulong ticket; + SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_NONE); + +//If there're many positions and account balance is negative + + if(PositionsTotal() > 0) + { + //Count the opened positions by type + int cntP = PositionsTotal(); + for(int i = cntP-1; i>=0; i--) + { + ticket = PositionGetTicket(i); + if(PositionSelectByTicket(ticket)) + { + if(PositionGetString(POSITION_SYMBOL)==mSymbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY + && PositionGetInteger(POSITION_MAGIC)==m_magic) + { + openedBuyPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN); + pCountBuy += 1; + } + + if(PositionGetString(POSITION_SYMBOL)==mSymbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL + && PositionGetInteger(POSITION_MAGIC)==m_magic) + { + openedSellPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN); + pCountSell += 1; + } + } + else + { + Print(GetLastError()); + } + } + } +//Count the orders by type + + int cntO = OrdersTotal(); + + for(int i = cntO-1; i>=0; i--) + { + + ticket = OrderGetTicket(i); + if(OrderSelect(ticket)) + { + if(OrderGetString(ORDER_SYMBOL)==mSymbol && OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP + && OrderGetInteger(ORDER_MAGIC)==m_magic) + { + oCountBuy += 1; + lastBuyOrderPrice = OrderGetDouble(ORDER_PRICE_OPEN); + } + + Print("ORDER_SYMBOL ", OrderGetString(ORDER_SYMBOL), " Real symbol ", mSymbol, " ORDER_TYPE ", OrderGetInteger(ORDER_TYPE), " Real type ", ORDER_TYPE_SELL_STOP, " Magic ", OrderGetInteger(ORDER_MAGIC), " Real magic ", m_magic); + if(OrderGetString(ORDER_SYMBOL)==mSymbol && OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP + && OrderGetInteger(ORDER_MAGIC)==m_magic) + { + oCountSell += 1; + lastSellOrderPrice = OrderGetDouble(ORDER_PRICE_OPEN); + } + } + else + { + Print("Last error code ", GetLastError()); + } + } + + double floatingProfitPercent = ((AccountInfoDouble(ACCOUNT_EQUITY) - AccountInfoDouble(ACCOUNT_BALANCE))*100)/AccountInfoDouble(ACCOUNT_BALANCE); +// Check if profit is at least the mMaxRiskPerTrade + +//The number of buy pending order should be twice the opened sell positions; and vice versa + realOCountBuy = pCountSell+1; + realOCountSell = pCountBuy+1; + totalBuy = pCountBuy+oCountBuy; + totalSell = pCountSell+oCountSell; + realTotalBuy = pCountSell+1; + realTotalSell = pCountBuy+1; + +Print("Signal conditions ........................................................................"); + + if(OrdersTotal() == 0 && PositionsTotal() == 0) + { + SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_BOTH); + Print("1 - Open both position"); + } + else + { + //If there's only one pending order left, close it. + if(OrdersTotal() >= 1 && PositionsTotal() == 0) + { + SetSignal(OFX_EXIT_SIGNAL, OFX_SIGNAL_ALL); + Print("2 - Exit if no opened position"); + } + else + { + //When there are multiple positions, check is the account is making enough profit + if(floatingProfitPercent > mMaxRiskPerTrade) + { + SetSignal(OFX_EXIT_SIGNAL, OFX_SIGNAL_ALL); + Print("3 - Exit on profit target"); + } + else + { + Print("realTotalSell ", realTotalSell, " > ", " totalSell ", totalSell," && ", " pCountBuy ",pCountBuy," > 0"); + if(realTotalSell > totalSell && pCountBuy > 0) + { + SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_SELL); + Print("4 - Sell order (", oCountSell, ") is less than it should be (", realOCountSell, ")"); + } + else + { + if(realTotalBuy > totalBuy && pCountSell > 0) + { + SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_BUY); + //mEntrySignals[0].SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_BUY); + Print("5 - Buy order (", oCountBuy, ") is less than it should be (", realOCountBuy, ")"); + } + } + } + } + } } //+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Frameworks/Framework_1.00/Indicators/AllIndicators.mqh b/Include/Nkanven/Frameworks/Framework_1.00/Indicators/AllIndicators.mqh deleted file mode 100644 index 2448cd2..0000000 --- a/Include/Nkanven/Frameworks/Framework_1.00/Indicators/AllIndicators.mqh +++ /dev/null @@ -1,15 +0,0 @@ -/* - AllIndicators.mqh - - Copyright 2013-2020, Orchard Forex - https://www.orchardforex.com - - -*/ - -#include "IndicatorBase.mqh" - -// -// Other signals go here -// -#include "Average/IndicatorMA.mqh" diff --git a/Include/Nkanven/Frameworks/Framework_1.00/Indicators/Average/IndicatorMA.mqh b/Include/Nkanven/Frameworks/Framework_1.00/Indicators/Average/IndicatorMA.mqh deleted file mode 100644 index 4dcd4ae..0000000 --- a/Include/Nkanven/Frameworks/Framework_1.00/Indicators/Average/IndicatorMA.mqh +++ /dev/null @@ -1,91 +0,0 @@ -/* - IndicatorMA.mqh - For framework version 1.0 - - Copyright 2013-2020, Orchard Forex - https://www.orchardforex.com - -*/ - -#include "../IndicatorBase.mqh" - -class CIndicatorMA : public CIndicatorBase { - -private: - -protected: // member variables - - int mPeriods; - int mShift; - ENUM_MA_METHOD mMethod; - ENUM_APPLIED_PRICE mAppliedPrice; - - // Only used for MQL5 - int mHandle; - -public: // constructors - - CIndicatorMA(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice) - : CIndicatorBase() - { Init(periods, shift, method, appliedPrice); } - CIndicatorMA(string symbol, ENUM_TIMEFRAMES timeframe, - int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice) - : CIndicatorBase(symbol, timeframe) - { Init(periods, shift, method, appliedPrice); } - ~CIndicatorMA(); - - virtual int Init(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice); - -public: - - virtual double GetData(const int buffer_num,const int index); - -}; - -CIndicatorMA::~CIndicatorMA() { - -#ifdef __MQL5__ - - if (mHandle!=INVALID_HANDLE) IndicatorRelease(mHandle); - -#endif - -} - -int CIndicatorMA::Init(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice) { - - if (InitResult()!=INIT_SUCCEEDED) return(InitResult()); - - mPeriods = periods; - mShift = shift; - mMethod = method; - mAppliedPrice = appliedPrice; - -#ifdef __MQL5__ - mHandle = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice); - if (mHandle==INVALID_HANDLE) return(InitError("Failed to create indicator handle", INIT_FAILED)); -#endif - - return(INIT_SUCCEEDED); - -} - -double CIndicatorMA::GetData(const int buffer_num,const int index) { - - double value = 0; -#ifdef __MQL4__ - value = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice, index); -#endif - -#ifdef __MQL5__ - double bufferData[]; - ArraySetAsSeries(bufferData, true); - int cnt = CopyBuffer(mHandle, buffer_num, index, 1, bufferData); - if (cnt>0) value = bufferData[0]; -#endif - - return(value); - -} - - diff --git a/Include/Nkanven/Frameworks/GDea/CommonBase.mqh b/Include/Nkanven/Frameworks/GDea/CommonBase.mqh new file mode 100644 index 0000000..46edb6a --- /dev/null +++ b/Include/Nkanven/Frameworks/GDea/CommonBase.mqh @@ -0,0 +1,78 @@ +/* + CommonBase.mqh + For framework version 1.0 + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + +*/ + +#define _INIT_CHECK_FAIL if (mInitResult!=INIT_SUCCEEDED) return(mInitResult); +#define _INIT_ERROR(msg) return(InitError(msg, INIT_PARAMETERS_INCORRECT)); +#define _INIT_ASSERT(condition, msg) if (!condition) return(InitError(msg, INIT_FAILED)); + +class CCommonBase { + +private: + +protected: // Members + + int mDigits; + string mSymbol; + ENUM_TIMEFRAMES mTimeframe; + + string mInitMessage; + int mInitResult; + +protected: // Constructors + + // + // Constructors + // + CCommonBase() { Init(_Symbol, (ENUM_TIMEFRAMES)_Period); } + CCommonBase(string symbol) { Init(symbol, (ENUM_TIMEFRAMES)_Period); } + CCommonBase(int timeframe) { Init(_Symbol, (ENUM_TIMEFRAMES)timeframe); } + CCommonBase(ENUM_TIMEFRAMES timeframe) { Init(_Symbol, timeframe); } + CCommonBase(string symbol, int timeframe) { Init(symbol, (ENUM_TIMEFRAMES)timeframe); } + CCommonBase(string symbol, ENUM_TIMEFRAMES timeframe) { Init(symbol, timeframe); } + + // + // Destructors + // + ~CCommonBase() {}; + + int Init(string symbol, ENUM_TIMEFRAMES timeframe); + +protected: // Functions + + int InitError(string initMessage, int initResult) + { mInitMessage = initMessage; + mInitResult = initResult; + if (initMessage!="") Print(initMessage); + return(initResult); } + + double PointsToDouble(int points) { return(points*SymbolInfoDouble(mSymbol, SYMBOL_POINT)); } + +public: // Properties + + int InitResult() { return(mInitResult); } + string InitMessage() { return(mInitMessage); } + +public: // Functions + + bool TradeAllowed() { return(SymbolInfoInteger(mSymbol, SYMBOL_TRADE_MODE)!=SYMBOL_TRADE_MODE_DISABLED); } + +}; + +int CCommonBase::Init(string symbol, ENUM_TIMEFRAMES timeframe) { + + InitError("", INIT_SUCCEEDED); + + mSymbol = symbol; + mTimeframe = timeframe; + mDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); + + return(INIT_SUCCEEDED); + +} + diff --git a/Include/Nkanven/Frameworks/GDea/ExpertBase.mqh b/Include/Nkanven/Frameworks/GDea/ExpertBase.mqh new file mode 100644 index 0000000..e5afc1d --- /dev/null +++ b/Include/Nkanven/Frameworks/GDea/ExpertBase.mqh @@ -0,0 +1,380 @@ +/* + ExpertBase.mqh + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + +*/ + + +#include "CommonBase.mqh" +#include "SignalBase.mqh" +#include "TPSLBase.mqh" +#include "Trade/Trade.mqh" + +class CExpertBase : public CCommonBase { + +protected: + + int mMagicNumber; + string mTradeComment; + + double mVolume; + + datetime mLastBarTime; + datetime mBarTime; + + ////Changed + // Arrays to hold the signal objects + CSignalBase *mEntrySignals[]; + CSignalBase *mExitSignals[]; + ////CSignalBase *mEntrySignal; + ////CSignalBase *mExitSignal; + + double mTakeProfitValue; + double mStopLossValue; + CTPSLBase *mTakeProfitObj; + CTPSLBase *mStopLossObj; + + CTradeCustom Trade; + +private: + +protected: + + virtual bool LoopMain(bool newBar, bool firstTime); + +protected: + + int Init(int magicNumber, string tradeComment); + +public: + + // + // Constructors + // + CExpertBase() : CCommonBase() + { Init(0, ""); } + CExpertBase(string symbol, int timeframe, int magicNumber, string tradeComment) + : CCommonBase(symbol, timeframe) + { Init(magicNumber, tradeComment); } + CExpertBase(string symbol, ENUM_TIMEFRAMES timeframe, int magicNumber, string tradeComment) + : CCommonBase(symbol, timeframe) + { Init(magicNumber, tradeComment); } + CExpertBase(int magicNumber, string tradeComment) + : CCommonBase() + { Init(magicNumber, tradeComment); } + + // + // Destructors + // + ~CExpertBase(); + +public: // Default properties + + // + // Assign the default values to the expert + // + virtual void SetVolume(double volume) { mVolume = volume; } + + virtual void SetTakeProfitValue(int takeProfitPoints) + { mTakeProfitValue = PointsToDouble(takeProfitPoints); } + virtual void SetTakeProfitObj(CTPSLBase *takeProfitObj) + { mTakeProfitObj = takeProfitObj; } + + virtual void SetStopLossValue(int stopLossPoints) + { mStopLossValue = PointsToDouble(stopLossPoints); } + virtual void SetStopLossObj(CTPSLBase *stopLossObj) + { mStopLossObj = stopLossObj; } + + virtual void SetTradeComment(string comment) { mTradeComment = comment; } + virtual void SetMagic(int magicNumber) { mMagicNumber = magicNumber; + Trade.SetExpertMagicNumber(magicNumber); } + +public: // Setup + + ////Changed + virtual void AddEntrySignal(CSignalBase *signal) { AddSignal(signal, mEntrySignals); } + virtual void AddExitSignal(CSignalBase *signal) { AddSignal(signal, mExitSignals); } + virtual void AddSignal(CSignalBase *signal, CSignalBase* &signals[]); + ////virtual void AddEntrySignal(CSignalBase *signal) { mEntrySignal=signal; } + ////virtual void AddExitSignal(CSignalBase *signal) { mExitSignal=signal; } + +public: // Event handlers + + virtual int OnInit(); + virtual void OnTick(); + virtual void OnTimer() { return; } + virtual double OnTester() { return(0.0); } + virtual void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {}; + +#ifdef __MQL5__ + virtual void OnTrade() { return; } + virtual void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { return; } + virtual int OnTesterInit() { return(INIT_SUCCEEDED); } + virtual void OnTesterPass() { return; } + virtual void OnTesterDeinit() { return; } + virtual void OnBookEvent() { return; } +#endif + +public: // Functions + + virtual void GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request); + ////New + virtual ENUM_OFX_SIGNAL_DIRECTION GetCurrentSignal(CSignalBase* &signals[], + ENUM_OFX_SIGNAL_TYPE signalType); + +}; + +CExpertBase::~CExpertBase() { + +} + +int CExpertBase::OnInit() { + + int i = 0; + for (i=ArraySize(mEntrySignals)-1; i>=0; i--) { + if (mEntrySignals[i].InitResult()!=INIT_SUCCEEDED) return(mEntrySignals[i].InitResult()); + } + for (i=ArraySize(mExitSignals)-1; i>=0; i--) { + if (mExitSignals[i].InitResult()!=INIT_SUCCEEDED) return(mExitSignals[i].InitResult()); + } + if (mTakeProfitObj!=NULL) { + if (mTakeProfitObj.InitResult()!=INIT_SUCCEEDED) return(mTakeProfitObj.InitResult()); + } + if (mStopLossObj!=NULL) { + if (mStopLossObj.InitResult()!=INIT_SUCCEEDED) return(mStopLossObj.InitResult()); + } + + return(INIT_SUCCEEDED); + +} + +int CExpertBase::Init(int magicNumber, string tradeComment) { + + if (mInitResult!=INIT_SUCCEEDED) return(mInitResult); + + mTradeComment = tradeComment; + SetMagic(magicNumber); + + mTakeProfitValue = 0.0; + mStopLossValue = 0.0; + + mLastBarTime = 0; + + ////New + ArrayResize(mEntrySignals, 0); // Just make sure these are initialised + ArrayResize(mExitSignals, 0); + + return(INIT_SUCCEEDED); + +} + +void CExpertBase::OnTick(void) { + + if (!TradeAllowed()) return; + + mBarTime = iTime(mSymbol, mTimeframe, 0); + + bool firstTime = (mLastBarTime==0); + bool newBar = (mBarTime!=mLastBarTime); + + if (LoopMain(newBar, firstTime)) { + mLastBarTime = mBarTime; + } + + return; + +} + +bool CExpertBase::LoopMain(bool newBar,bool firstTime) { + + // + // To start I will only trade on a new bar + // and not on the first bar after start + // + if (!newBar) return(true); + if (firstTime) return(true); + + // + // Update the signals + // + ////Changed + ENUM_OFX_SIGNAL_DIRECTION entrySignal = GetCurrentSignal(mEntrySignals, OFX_ENTRY_SIGNAL); + ENUM_OFX_SIGNAL_DIRECTION exitSignal = GetCurrentSignal(mExitSignals, OFX_EXIT_SIGNAL); + ////if (mEntrySignal!=NULL) mEntrySignal.UpdateSignal(); + ////if (mEntrySignal!=mExitSignal) { + //// if (mExitSignal!=NULL) mExitSignal.UpdateSignal(); + ////} + + // + // Should any trades be closed + // + ////Changed + if (exitSignal==OFX_SIGNAL_BOTH) { + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + } else + if (exitSignal==OFX_SIGNAL_BUY) { + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + } else + if (exitSignal==OFX_SIGNAL_SELL) { + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + } + ////if (mExitSignal!=NULL) { + //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BOTH) { + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + //// } else + //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BUY) { + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + //// } else + //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_SELL) { + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + //// } + ////} + + // + // Should a trade be opened + // + MqlTradeRequest request = {}; // Just initialising + ////Changed + if (entrySignal==OFX_SIGNAL_BOTH) { + + GetMarketPrices(ORDER_TYPE_BUY, request); + Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); + + GetMarketPrices(ORDER_TYPE_SELL, request); + Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); + + } else + if (entrySignal==OFX_SIGNAL_BUY) { + + GetMarketPrices(ORDER_TYPE_BUY, request); + Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); + + } else + if (entrySignal==OFX_SIGNAL_SELL) { + + GetMarketPrices(ORDER_TYPE_SELL, request); + Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); + + } +//// if (mEntrySignal!=NULL) { +//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BOTH) { +//// +//// GetMarketPrices(ORDER_TYPE_BUY, request); +//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// GetMarketPrices(ORDER_TYPE_SELL, request); +//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// } else +//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BUY) { +//// +//// GetMarketPrices(ORDER_TYPE_BUY, request); +//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// } else +//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_SELL) { +//// +//// GetMarketPrices(ORDER_TYPE_SELL, request); +//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// } +//// } + + return(true); + +} + +void CExpertBase::GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request) { + + double sl = (mStopLossObj==NULL) ? mStopLossValue : mStopLossObj.GetStopLoss(); + double tp = (mTakeProfitObj==NULL) ? mTakeProfitValue : mTakeProfitObj.GetTakeProfit(); + + if (orderType==ORDER_TYPE_BUY) { + if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_ASK); + request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price+tp, mDigits); + request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price-sl, mDigits); + } + + if (orderType==ORDER_TYPE_SELL) { + if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_BID); + request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits); + request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits); + } + + return; + +} + +////New +void CExpertBase::AddSignal(CSignalBase *signal, CSignalBase* &signals[]) { + + int index = ArraySize(signals); + ArrayResize(signals, index+1); + signals[index] = signal; + +} + +////New +ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalBase* &signals[], + ENUM_OFX_SIGNAL_TYPE signalType) { + + ENUM_OFX_SIGNAL_DIRECTION result = OFX_SIGNAL_NONE; + ENUM_OFX_SIGNAL_DIRECTION r2 = OFX_SIGNAL_NONE; // Just working value + int index = ArraySize(signals); + + if (index<=0) { + + return(result); + + } else { + + signals[0].UpdateSignal(); + result = signals[0].GetSignal(signalType); + + // I have chosen to update all signals in case there is some + // behavour that needs it. The penalty is some performance + // If performance is an issue just add an exit inside the loop + // as the commented line + for (int i = 1; i0); +} + +bool CTradeCustom::Sell(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="") { + if (price==0.0) price = SellPrice(symbol); + int ticket = OrderSend(symbol, ORDER_TYPE_SELL, volume, price, 0, sl, tp, comment, mMagic); + return(ticket>0); +} + +bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const int deviation=ULONG_MAX) { + + int slippage = (deviation==ULONG_MAX) ? 0 : deviation; + + bool result = true; + int cnt = OrdersTotal(); + for (int i = cnt-1; i>=0; i--) { + if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { + if (OrderSymbol()==symbol && OrderMagicNumber()==mMagic && OrderType()==positionType) { + result &= OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), slippage); + } + } + } + + return(result); + +} + +////New +void CTradeCustom::PositionCountByType(const string symbol, int &count[]) { + + ArrayResize(count, 6); + ArrayInitialize(count, 0); + int cnt = OrdersTotal(); + for (int i = cnt-1; i>=0; i--) { + if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { + if (OrderSymbol()==symbol && OrderMagicNumber()==mMagic) { + count[(int)OrderType()]++; + } + } + } + + return; + +} diff --git a/Include/Nkanven/Frameworks/GDea/Trade/Trade_mql5.mqh b/Include/Nkanven/Frameworks/GDea/Trade/Trade_mql5.mqh new file mode 100644 index 0000000..3bae1c9 --- /dev/null +++ b/Include/Nkanven/Frameworks/GDea/Trade/Trade_mql5.mqh @@ -0,0 +1,66 @@ +/* + Trade.mqh + (For MQL5) + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + +*/ + +#include + +class CTradeCustom : public CTrade { + +private: + +protected: // member variables + +public: // constructors + +public: + + bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const ulong deviation=ULONG_MAX); + ////New + void PositionCountByType(const string symbol, int &count[]); + +}; + +bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const ulong deviation=ULONG_MAX) { + + bool result = true; + int cnt = PositionsTotal(); + for (int i = cnt-1; i>=0; i--) { + ulong ticket = PositionGetTicket(i); + if (PositionSelectByTicket(ticket)) { + if (PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_TYPE)==positionType && PositionGetInteger(POSITION_MAGIC)==m_magic) { + result &= PositionClose(ticket, deviation); + } + } else { + m_result.retcode=TRADE_RETCODE_REJECT; + result = false; + } + } + + return(result); + +} + +////New +void CTradeCustom::PositionCountByType(const string symbol, int &count[]) { + + ArrayResize(count, 6); + ArrayInitialize(count, 0); + + int cnt = PositionsTotal(); + for (int i = cnt-1; i>=0; i--) { + ulong ticket = PositionGetTicket(i); + if (PositionSelectByTicket(ticket)) { + if (PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_MAGIC)==m_magic) { + count[(int)PositionGetInteger(POSITION_TYPE)]++; + } + } + } + + return; + +} diff --git a/Include/Nkanven/Frameworks/GDea/Updates.txt b/Include/Nkanven/Frameworks/GDea/Updates.txt new file mode 100644 index 0000000..281bf10 --- /dev/null +++ b/Include/Nkanven/Frameworks/GDea/Updates.txt @@ -0,0 +1,7 @@ +Version 2.03 + +Added macros to CommonBase to standardise init checking + +Moved base classes up one level and removed unnecessary folders + +Updated framework number \ No newline at end of file diff --git a/Include/Nkanven/Frameworks/GDeaFramework.mqh b/Include/Nkanven/Frameworks/GDeaFramework.mqh new file mode 100644 index 0000000..d2d0187 --- /dev/null +++ b/Include/Nkanven/Frameworks/GDeaFramework.mqh @@ -0,0 +1,12 @@ +//+------------------------------------------------------------------+ +//| GDeaFramework.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + + +#ifndef _FRAMEWORK_VERSION_ + #include "GDea/Framework.mqh" +#endif diff --git a/Include/Nkanven/Frameworks/Gervis/CommonBase.mqh b/Include/Nkanven/Frameworks/Gervis/CommonBase.mqh new file mode 100644 index 0000000..46edb6a --- /dev/null +++ b/Include/Nkanven/Frameworks/Gervis/CommonBase.mqh @@ -0,0 +1,78 @@ +/* + CommonBase.mqh + For framework version 1.0 + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + +*/ + +#define _INIT_CHECK_FAIL if (mInitResult!=INIT_SUCCEEDED) return(mInitResult); +#define _INIT_ERROR(msg) return(InitError(msg, INIT_PARAMETERS_INCORRECT)); +#define _INIT_ASSERT(condition, msg) if (!condition) return(InitError(msg, INIT_FAILED)); + +class CCommonBase { + +private: + +protected: // Members + + int mDigits; + string mSymbol; + ENUM_TIMEFRAMES mTimeframe; + + string mInitMessage; + int mInitResult; + +protected: // Constructors + + // + // Constructors + // + CCommonBase() { Init(_Symbol, (ENUM_TIMEFRAMES)_Period); } + CCommonBase(string symbol) { Init(symbol, (ENUM_TIMEFRAMES)_Period); } + CCommonBase(int timeframe) { Init(_Symbol, (ENUM_TIMEFRAMES)timeframe); } + CCommonBase(ENUM_TIMEFRAMES timeframe) { Init(_Symbol, timeframe); } + CCommonBase(string symbol, int timeframe) { Init(symbol, (ENUM_TIMEFRAMES)timeframe); } + CCommonBase(string symbol, ENUM_TIMEFRAMES timeframe) { Init(symbol, timeframe); } + + // + // Destructors + // + ~CCommonBase() {}; + + int Init(string symbol, ENUM_TIMEFRAMES timeframe); + +protected: // Functions + + int InitError(string initMessage, int initResult) + { mInitMessage = initMessage; + mInitResult = initResult; + if (initMessage!="") Print(initMessage); + return(initResult); } + + double PointsToDouble(int points) { return(points*SymbolInfoDouble(mSymbol, SYMBOL_POINT)); } + +public: // Properties + + int InitResult() { return(mInitResult); } + string InitMessage() { return(mInitMessage); } + +public: // Functions + + bool TradeAllowed() { return(SymbolInfoInteger(mSymbol, SYMBOL_TRADE_MODE)!=SYMBOL_TRADE_MODE_DISABLED); } + +}; + +int CCommonBase::Init(string symbol, ENUM_TIMEFRAMES timeframe) { + + InitError("", INIT_SUCCEEDED); + + mSymbol = symbol; + mTimeframe = timeframe; + mDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); + + return(INIT_SUCCEEDED); + +} + diff --git a/Include/Nkanven/Frameworks/Gervis/ExpertBase.mqh b/Include/Nkanven/Frameworks/Gervis/ExpertBase.mqh new file mode 100644 index 0000000..e5afc1d --- /dev/null +++ b/Include/Nkanven/Frameworks/Gervis/ExpertBase.mqh @@ -0,0 +1,380 @@ +/* + ExpertBase.mqh + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + +*/ + + +#include "CommonBase.mqh" +#include "SignalBase.mqh" +#include "TPSLBase.mqh" +#include "Trade/Trade.mqh" + +class CExpertBase : public CCommonBase { + +protected: + + int mMagicNumber; + string mTradeComment; + + double mVolume; + + datetime mLastBarTime; + datetime mBarTime; + + ////Changed + // Arrays to hold the signal objects + CSignalBase *mEntrySignals[]; + CSignalBase *mExitSignals[]; + ////CSignalBase *mEntrySignal; + ////CSignalBase *mExitSignal; + + double mTakeProfitValue; + double mStopLossValue; + CTPSLBase *mTakeProfitObj; + CTPSLBase *mStopLossObj; + + CTradeCustom Trade; + +private: + +protected: + + virtual bool LoopMain(bool newBar, bool firstTime); + +protected: + + int Init(int magicNumber, string tradeComment); + +public: + + // + // Constructors + // + CExpertBase() : CCommonBase() + { Init(0, ""); } + CExpertBase(string symbol, int timeframe, int magicNumber, string tradeComment) + : CCommonBase(symbol, timeframe) + { Init(magicNumber, tradeComment); } + CExpertBase(string symbol, ENUM_TIMEFRAMES timeframe, int magicNumber, string tradeComment) + : CCommonBase(symbol, timeframe) + { Init(magicNumber, tradeComment); } + CExpertBase(int magicNumber, string tradeComment) + : CCommonBase() + { Init(magicNumber, tradeComment); } + + // + // Destructors + // + ~CExpertBase(); + +public: // Default properties + + // + // Assign the default values to the expert + // + virtual void SetVolume(double volume) { mVolume = volume; } + + virtual void SetTakeProfitValue(int takeProfitPoints) + { mTakeProfitValue = PointsToDouble(takeProfitPoints); } + virtual void SetTakeProfitObj(CTPSLBase *takeProfitObj) + { mTakeProfitObj = takeProfitObj; } + + virtual void SetStopLossValue(int stopLossPoints) + { mStopLossValue = PointsToDouble(stopLossPoints); } + virtual void SetStopLossObj(CTPSLBase *stopLossObj) + { mStopLossObj = stopLossObj; } + + virtual void SetTradeComment(string comment) { mTradeComment = comment; } + virtual void SetMagic(int magicNumber) { mMagicNumber = magicNumber; + Trade.SetExpertMagicNumber(magicNumber); } + +public: // Setup + + ////Changed + virtual void AddEntrySignal(CSignalBase *signal) { AddSignal(signal, mEntrySignals); } + virtual void AddExitSignal(CSignalBase *signal) { AddSignal(signal, mExitSignals); } + virtual void AddSignal(CSignalBase *signal, CSignalBase* &signals[]); + ////virtual void AddEntrySignal(CSignalBase *signal) { mEntrySignal=signal; } + ////virtual void AddExitSignal(CSignalBase *signal) { mExitSignal=signal; } + +public: // Event handlers + + virtual int OnInit(); + virtual void OnTick(); + virtual void OnTimer() { return; } + virtual double OnTester() { return(0.0); } + virtual void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {}; + +#ifdef __MQL5__ + virtual void OnTrade() { return; } + virtual void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { return; } + virtual int OnTesterInit() { return(INIT_SUCCEEDED); } + virtual void OnTesterPass() { return; } + virtual void OnTesterDeinit() { return; } + virtual void OnBookEvent() { return; } +#endif + +public: // Functions + + virtual void GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request); + ////New + virtual ENUM_OFX_SIGNAL_DIRECTION GetCurrentSignal(CSignalBase* &signals[], + ENUM_OFX_SIGNAL_TYPE signalType); + +}; + +CExpertBase::~CExpertBase() { + +} + +int CExpertBase::OnInit() { + + int i = 0; + for (i=ArraySize(mEntrySignals)-1; i>=0; i--) { + if (mEntrySignals[i].InitResult()!=INIT_SUCCEEDED) return(mEntrySignals[i].InitResult()); + } + for (i=ArraySize(mExitSignals)-1; i>=0; i--) { + if (mExitSignals[i].InitResult()!=INIT_SUCCEEDED) return(mExitSignals[i].InitResult()); + } + if (mTakeProfitObj!=NULL) { + if (mTakeProfitObj.InitResult()!=INIT_SUCCEEDED) return(mTakeProfitObj.InitResult()); + } + if (mStopLossObj!=NULL) { + if (mStopLossObj.InitResult()!=INIT_SUCCEEDED) return(mStopLossObj.InitResult()); + } + + return(INIT_SUCCEEDED); + +} + +int CExpertBase::Init(int magicNumber, string tradeComment) { + + if (mInitResult!=INIT_SUCCEEDED) return(mInitResult); + + mTradeComment = tradeComment; + SetMagic(magicNumber); + + mTakeProfitValue = 0.0; + mStopLossValue = 0.0; + + mLastBarTime = 0; + + ////New + ArrayResize(mEntrySignals, 0); // Just make sure these are initialised + ArrayResize(mExitSignals, 0); + + return(INIT_SUCCEEDED); + +} + +void CExpertBase::OnTick(void) { + + if (!TradeAllowed()) return; + + mBarTime = iTime(mSymbol, mTimeframe, 0); + + bool firstTime = (mLastBarTime==0); + bool newBar = (mBarTime!=mLastBarTime); + + if (LoopMain(newBar, firstTime)) { + mLastBarTime = mBarTime; + } + + return; + +} + +bool CExpertBase::LoopMain(bool newBar,bool firstTime) { + + // + // To start I will only trade on a new bar + // and not on the first bar after start + // + if (!newBar) return(true); + if (firstTime) return(true); + + // + // Update the signals + // + ////Changed + ENUM_OFX_SIGNAL_DIRECTION entrySignal = GetCurrentSignal(mEntrySignals, OFX_ENTRY_SIGNAL); + ENUM_OFX_SIGNAL_DIRECTION exitSignal = GetCurrentSignal(mExitSignals, OFX_EXIT_SIGNAL); + ////if (mEntrySignal!=NULL) mEntrySignal.UpdateSignal(); + ////if (mEntrySignal!=mExitSignal) { + //// if (mExitSignal!=NULL) mExitSignal.UpdateSignal(); + ////} + + // + // Should any trades be closed + // + ////Changed + if (exitSignal==OFX_SIGNAL_BOTH) { + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + } else + if (exitSignal==OFX_SIGNAL_BUY) { + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + } else + if (exitSignal==OFX_SIGNAL_SELL) { + Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + } + ////if (mExitSignal!=NULL) { + //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BOTH) { + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + //// } else + //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BUY) { + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); + //// } else + //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_SELL) { + //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); + //// } + ////} + + // + // Should a trade be opened + // + MqlTradeRequest request = {}; // Just initialising + ////Changed + if (entrySignal==OFX_SIGNAL_BOTH) { + + GetMarketPrices(ORDER_TYPE_BUY, request); + Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); + + GetMarketPrices(ORDER_TYPE_SELL, request); + Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); + + } else + if (entrySignal==OFX_SIGNAL_BUY) { + + GetMarketPrices(ORDER_TYPE_BUY, request); + Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); + + } else + if (entrySignal==OFX_SIGNAL_SELL) { + + GetMarketPrices(ORDER_TYPE_SELL, request); + Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); + + } +//// if (mEntrySignal!=NULL) { +//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BOTH) { +//// +//// GetMarketPrices(ORDER_TYPE_BUY, request); +//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// GetMarketPrices(ORDER_TYPE_SELL, request); +//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// } else +//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BUY) { +//// +//// GetMarketPrices(ORDER_TYPE_BUY, request); +//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// } else +//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_SELL) { +//// +//// GetMarketPrices(ORDER_TYPE_SELL, request); +//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); +//// +//// } +//// } + + return(true); + +} + +void CExpertBase::GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request) { + + double sl = (mStopLossObj==NULL) ? mStopLossValue : mStopLossObj.GetStopLoss(); + double tp = (mTakeProfitObj==NULL) ? mTakeProfitValue : mTakeProfitObj.GetTakeProfit(); + + if (orderType==ORDER_TYPE_BUY) { + if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_ASK); + request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price+tp, mDigits); + request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price-sl, mDigits); + } + + if (orderType==ORDER_TYPE_SELL) { + if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_BID); + request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits); + request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits); + } + + return; + +} + +////New +void CExpertBase::AddSignal(CSignalBase *signal, CSignalBase* &signals[]) { + + int index = ArraySize(signals); + ArrayResize(signals, index+1); + signals[index] = signal; + +} + +////New +ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalBase* &signals[], + ENUM_OFX_SIGNAL_TYPE signalType) { + + ENUM_OFX_SIGNAL_DIRECTION result = OFX_SIGNAL_NONE; + ENUM_OFX_SIGNAL_DIRECTION r2 = OFX_SIGNAL_NONE; // Just working value + int index = ArraySize(signals); + + if (index<=0) { + + return(result); + + } else { + + signals[0].UpdateSignal(); + result = signals[0].GetSignal(signalType); + + // I have chosen to update all signals in case there is some + // behavour that needs it. The penalty is some performance + // If performance is an issue just add an exit inside the loop + // as the commented line + for (int i = 1; i0); +} + +bool CTradeCustom::Sell(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="") { + if (price==0.0) price = SellPrice(symbol); + int ticket = OrderSend(symbol, ORDER_TYPE_SELL, volume, price, 0, sl, tp, comment, mMagic); + return(ticket>0); +} + +bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const int deviation=ULONG_MAX) { + + int slippage = (deviation==ULONG_MAX) ? 0 : deviation; + + bool result = true; + int cnt = OrdersTotal(); + for (int i = cnt-1; i>=0; i--) { + if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { + if (OrderSymbol()==symbol && OrderMagicNumber()==mMagic && OrderType()==positionType) { + result &= OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), slippage); + } + } + } + + return(result); + +} + +////New +void CTradeCustom::PositionCountByType(const string symbol, int &count[]) { + + ArrayResize(count, 6); + ArrayInitialize(count, 0); + int cnt = OrdersTotal(); + for (int i = cnt-1; i>=0; i--) { + if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { + if (OrderSymbol()==symbol && OrderMagicNumber()==mMagic) { + count[(int)OrderType()]++; + } + } + } + + return; + +} diff --git a/Include/Nkanven/Frameworks/Gervis/Trade/Trade_mql5.mqh b/Include/Nkanven/Frameworks/Gervis/Trade/Trade_mql5.mqh new file mode 100644 index 0000000..3bae1c9 --- /dev/null +++ b/Include/Nkanven/Frameworks/Gervis/Trade/Trade_mql5.mqh @@ -0,0 +1,66 @@ +/* + Trade.mqh + (For MQL5) + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + +*/ + +#include + +class CTradeCustom : public CTrade { + +private: + +protected: // member variables + +public: // constructors + +public: + + bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const ulong deviation=ULONG_MAX); + ////New + void PositionCountByType(const string symbol, int &count[]); + +}; + +bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const ulong deviation=ULONG_MAX) { + + bool result = true; + int cnt = PositionsTotal(); + for (int i = cnt-1; i>=0; i--) { + ulong ticket = PositionGetTicket(i); + if (PositionSelectByTicket(ticket)) { + if (PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_TYPE)==positionType && PositionGetInteger(POSITION_MAGIC)==m_magic) { + result &= PositionClose(ticket, deviation); + } + } else { + m_result.retcode=TRADE_RETCODE_REJECT; + result = false; + } + } + + return(result); + +} + +////New +void CTradeCustom::PositionCountByType(const string symbol, int &count[]) { + + ArrayResize(count, 6); + ArrayInitialize(count, 0); + + int cnt = PositionsTotal(); + for (int i = cnt-1; i>=0; i--) { + ulong ticket = PositionGetTicket(i); + if (PositionSelectByTicket(ticket)) { + if (PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_MAGIC)==m_magic) { + count[(int)PositionGetInteger(POSITION_TYPE)]++; + } + } + } + + return; + +} diff --git a/Include/Nkanven/Frameworks/Gervis/Updates.txt b/Include/Nkanven/Frameworks/Gervis/Updates.txt new file mode 100644 index 0000000..281bf10 --- /dev/null +++ b/Include/Nkanven/Frameworks/Gervis/Updates.txt @@ -0,0 +1,7 @@ +Version 2.03 + +Added macros to CommonBase to standardise init checking + +Moved base classes up one level and removed unnecessary folders + +Updated framework number \ No newline at end of file diff --git a/Include/Nkanven/Frameworks/GervisFrame.mqh b/Include/Nkanven/Frameworks/GervisFrame.mqh new file mode 100644 index 0000000..faa324f --- /dev/null +++ b/Include/Nkanven/Frameworks/GervisFrame.mqh @@ -0,0 +1,12 @@ +//+------------------------------------------------------------------+ +//| GervisFrame.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + + +#ifndef _FRAMEWORK_VERSION_ + #include "Gervis/Framework.mqh" +#endif \ No newline at end of file diff --git a/Include/Nkanven/Frameworks/GridEA/ExpertBase.mqh b/Include/Nkanven/Frameworks/GridEA/ExpertBase.mqh index 55c8d6a..571f73c 100644 --- a/Include/Nkanven/Frameworks/GridEA/ExpertBase.mqh +++ b/Include/Nkanven/Frameworks/GridEA/ExpertBase.mqh @@ -31,37 +31,39 @@ protected: double mMaxLotSize; double mMinLotSize; double mMaxRiskPerTrade; - + double mProfitPercent; + double mTargetProfit; double lastBuyOrderPrice; double lastSellOrderPrice; double openedBuyPositionPrice; double openedSellPositionPrice; - + double pendingOrderPrice; ENUM_TRADING_SESSION mUseTradingSession; ENUM_RISK_DEFAULT_SIZE mRiskDefaultSize; ENUM_RISK_BASE mRiskBase; - enum ENUM_NAV_SIGNAL_TYPE + enum ENUM_OFX_SIGNAL_TYPE { - NAV_ENTRY_SIGNAL, - NAV_EXIT_SIGNAL + OFX_ENTRY_SIGNAL, + OFX_EXIT_SIGNAL }; - ENUM_NAV_SIGNAL_TYPE signalType; + ENUM_OFX_SIGNAL_TYPE signalType; - enum ENUM_NAV_SIGNAL_DIRECTION + enum ENUM_OFX_SIGNAL_DIRECTION { - NAV_SIGNAL_NONE = 0, - NAV_SIGNAL_BUY = 1, - NAV_SIGNAL_SELL = 2, - NAV_SIGNAL_BOTH = 3, - NAV_SIGNAL_ALL = 4 + OFX_SIGNAL_NONE = 0, + OFX_SIGNAL_BUY = 1, + OFX_SIGNAL_SELL = 2, + OFX_SIGNAL_BOTH = 3, + OFX_SIGNAL_ALL = 4 }; - ENUM_NAV_SIGNAL_DIRECTION signalDirection; + ENUM_OFX_SIGNAL_DIRECTION entrySignal; + ENUM_OFX_SIGNAL_DIRECTION exitSignal; datetime mLastBarTime; datetime mBarTime; @@ -87,6 +89,7 @@ private: protected: virtual bool LoopMain(bool newBar, bool firstTime); + virtual void GetPendingOrderPrice(ENUM_OFX_SIGNAL_DIRECTION tradeType); protected: @@ -146,6 +149,7 @@ public: // Default properties virtual void SetMaxLotSize(double maxLotSize) {mMaxLotSize = maxLotSize;} virtual void SetMinLotSize(double minLotSize) {mMinLotSize = minLotSize;} virtual void SetMaxRiskPerTrade(double maxRiskPerTrade) {mMaxRiskPerTrade = maxRiskPerTrade;} + virtual void SetProfitPercent(double profitPercent) {mProfitPercent = profitPercent;} virtual void SetUseTradingSession(ENUM_TRADING_SESSION useTradingSession) {mUseTradingSession = useTradingSession;} @@ -163,11 +167,6 @@ public: // Setup virtual bool IsTradingTime(); virtual bool CheckTradingSession(); - virtual double getLastBuyOrderPrice() {return lastBuyOrderPrice;} - virtual double getLastSellOrderPrice() {return lastSellOrderPrice;} - virtual double getOpenedBuyPositionPrice() {return openedBuyPositionPrice;} - virtual double getOpenedSellPositionPrice() {return openedSellPositionPrice;} - ////virtual void AddEntrySignal(CSignalBase *signal) { mEntrySignal=signal; } ////virtual void AddExitSignal(CSignalBase *signal) { mExitSignal=signal; } @@ -198,6 +197,11 @@ public: // Functions virtual ENUM_OFX_SIGNAL_DIRECTION GetCurrentSignal(CSignalGrid* &signals[], ENUM_OFX_SIGNAL_TYPE signalType); + virtual double getLastBuyOrderPrice() {return lastBuyOrderPrice;} + virtual double getLastSellOrderPrice() {return lastSellOrderPrice;} + virtual double getOpenedBuyPositionPrice() {return openedBuyPositionPrice;} + virtual double getOpenedSellPositionPrice() {return openedSellPositionPrice;} + }; //+------------------------------------------------------------------+ @@ -280,7 +284,6 @@ void CExpertBase::OnTick(void) bool newBar = (mBarTime!=mLastBarTime); TradeWatcher(); -Print("signalDirection after TradeWatcher ", signalDirection); if(LoopMain(newBar, firstTime)) { mLastBarTime = mBarTime; @@ -309,151 +312,108 @@ bool CExpertBase::LoopMain(bool newBar,bool firstTime) // Update the signals // ////Changed - ENUM_OFX_SIGNAL_DIRECTION entrySignal = GetCurrentSignal(mEntrySignals, OFX_ENTRY_SIGNAL); - ENUM_OFX_SIGNAL_DIRECTION exitSignal = GetCurrentSignal(mExitSignals, OFX_EXIT_SIGNAL); - /*if(mEntrySignals[0]!=NULL) - mEntrySignals[0].UpdateSignal(); - if(mEntrySignals[0]!=mExitSignals[0]) - { - if(mEntrySignals[0]!=NULL) - mEntrySignals[0].UpdateSignal(); - }*/ + /* ENUM_OFX_SIGNAL_DIRECTION entrySignal = GetCurrentSignal(mEntrySignals, OFX_ENTRY_SIGNAL); + ENUM_OFX_SIGNAL_DIRECTION exitSignal = GetCurrentSignal(mExitSignals, OFX_EXIT_SIGNAL);****/ -// -// Should any trades be closed -// -////Changed -/* - if(exitSignal==OFX_SIGNAL_BOTH) - { - Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); - Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); - } - else - if(exitSignal==OFX_SIGNAL_BUY) - { - Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); - } - else - if(exitSignal==OFX_SIGNAL_SELL) - { - Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); - } - if(exitSignal==OFX_SIGNAL_ALL) - { - Trade.PositionCloseAll(); - Trade.OrderCloseAll(); - } -*/ -////if (mExitSignal!=NULL) { -//// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BOTH) { -//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); -//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); -//// } else -//// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BUY) { -//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); -//// } else -//// if (mExitSignal.ExitSignal()==OFX_SIGNAL_SELL) { -//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); -//// } -////} + Print("entrySignal ", entrySignal, ", exitSignal ", exitSignal); // // Should a trade be opened // MqlTradeRequest request = {}; // Just initialising - double buyPrice, sellPrice, SLPoints=0; + double sellPrice, buyPrice, SLPoints=0; int GripPips = mGridGap; + double TakeProfitPoint = GripPips*_Point; + long offset = SymbolInfoInteger(mSymbol, SYMBOL_TRADE_STOPS_LEVEL); + Print("Take profit point ", TakeProfitPoint); + Print("Offset levelt ", offset, " Spread ", SymbolInfoInteger(mSymbol, SYMBOL_SPREAD)); LotSize(GripPips); -////Changed + double AskPrice = SymbolInfoDouble(mSymbol,SYMBOL_ASK); + double BidPrice = SymbolInfoDouble(mSymbol,SYMBOL_BID); + bool retry = true; - Print("Entry signal for Both ", NAV_SIGNAL_BOTH, " Entry for OFX_SIGNAL_BUY ", NAV_SIGNAL_BUY, " Actual ", signalDirection); - Print("signalDirection ", signalDirection); - if(signalDirection==NAV_SIGNAL_BOTH) + +//GetMarketPrices(ORDER_TYPE_BUY, request); + + +//GetMarketPrices(ORDER_TYPE_SELL_STOP, request); + sellPrice = BidPrice - TakeProfitPoint; + buyPrice = AskPrice + TakeProfitPoint; + if(entrySignal==OFX_SIGNAL_BOTH) { - double AskPrice = SymbolInfoDouble(Symbol(),SYMBOL_ASK); - double BidPrice = SymbolInfoDouble(Symbol(),SYMBOL_BID); + request.price = NormalizeDouble(sellPrice, mDigits); - Print("m Grid pip ", GripPips, " Point ", _Point, " TP point ", TakeProfitPoint); - buyPrice = AskPrice + TakeProfitPoint; - sellPrice = BidPrice - TakeProfitPoint; - - Print("m Grid pip ", GripPips, " Point ", _Point); - - Print(" Buy price ", buyPrice, " TP normalized ", NormalizeDouble(buyPrice + TakeProfitPoint, mDigits)); - //SLPoints=MathCeil(buyPrice-GripPips); - - //GetMarketPrices(ORDER_TYPE_SELL, request); - //Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); - GetMarketPrices(ORDER_TYPE_BUY, request); - request.tp = NormalizeDouble(request.price + TakeProfitPoint, mDigits); - Trade.Buy(mVolume, mSymbol, request.price, request.sl); - - GetMarketPrices(ORDER_TYPE_SELL_STOP, request); - request.price = sellPrice; - request.tp = NormalizeDouble(sellPrice - TakeProfitPoint, mDigits); - Trade.SellStop(mVolume, request.price, mSymbol, request.sl); + if(Trade.SellStop(mVolume, request.price, mSymbol)) + { + request.price = NormalizeDouble(AskPrice, mDigits); + Trade.Buy(mVolume, mSymbol,request.price); + return(true); + } + else + { + Print("Get last error code ", GetLastError()); + return(true); + } } + else - if(signalDirection==NAV_SIGNAL_BUY) + if(entrySignal==OFX_SIGNAL_BUY) { //If there's a pending order, get the last order's price else get the position price Print("Trying to open a buy"); - buyPrice = getLastBuyOrderPrice()?getLastBuyOrderPrice():getOpenedBuyPositionPrice(); - request.price = buyPrice+TakeProfitPoint; - request.sl = 0.0; - request.tp = NormalizeDouble(buyPrice + TakeProfitPoint, mDigits); - GetMarketPrices(ORDER_TYPE_BUY_STOP, request); - Trade.BuyStop(mVolume, request.price, mSymbol, request.sl); + //GetMarketPrices(ORDER_TYPE_BUY_STOP, request); + Print("openedBuyPositionPrice ", openedBuyPositionPrice, " lastBuyOrderPrice ", lastBuyOrderPrice); + buyPrice = (lastBuyOrderPrice == 0.0) ? openedBuyPositionPrice : lastBuyOrderPrice; + request.price = NormalizeDouble(buyPrice+TakeProfitPoint, mDigits); + + if(!Trade.BuyStop(mVolume, request.price, mSymbol)) + { + while(retry) + { + if(Trade.Buy(mVolume, mSymbol, NormalizeDouble(AskPrice, mDigits))) + { + retry = false; + } + } + } + return(true); } else - if(signalDirection==NAV_SIGNAL_SELL) + if(entrySignal==OFX_SIGNAL_SELL) { Print("Trying to open a sell"); - sellPrice = getLastSellOrderPrice()?getLastSellOrderPrice():getOpenedSellPositionPrice(); - request.price = sellPrice-TakeProfitPoint; - request.sl = 0.0; - request.tp = NormalizeDouble(sellPrice - TakeProfitPoint, mDigits); - GetMarketPrices(ORDER_TYPE_SELL_STOP, request); - Trade.SellStop(mVolume, request.price, mSymbol, request.sl); + + //GetMarketPrices(ORDER_TYPE_SELL_STOP, request); + Print("openedSellPositionPrice ", openedSellPositionPrice, " lastSellOrderPrice ", lastSellOrderPrice); + sellPrice = (lastSellOrderPrice == 0.0) ? openedSellPositionPrice : lastSellOrderPrice; + Print("sellPrice ", sellPrice); + request.price = NormalizeDouble(sellPrice-TakeProfitPoint, mDigits); + Print("request.price ", request.price); + + if(!Trade.SellStop(mVolume, NormalizeDouble(request.price,mDigits), mSymbol)) + { + while(retry) + { + if(Trade.Sell(mVolume, mSymbol, NormalizeDouble(BidPrice, mDigits))) + { + retry = false; + } + } + } + return(true); } - if(signalDirection==NAV_SIGNAL_ALL) + + if(exitSignal==OFX_SIGNAL_ALL) { Trade.OrderCloseAll(); Trade.PositionCloseAll(); } -//// if (mEntrySignal!=NULL) { -//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BOTH) { -//// -//// GetMarketPrices(ORDER_TYPE_BUY, request); -//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); -//// -//// GetMarketPrices(ORDER_TYPE_SELL, request); -//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); -//// -//// } else -//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BUY) { -//// -//// GetMarketPrices(ORDER_TYPE_BUY, request); -//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); -//// -//// } else -//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_SELL) { -//// -//// GetMarketPrices(ORDER_TYPE_SELL, request); -//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); -//// -//// } -//// } - -//mEntrySignals[0].SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_NONE); -//mEntrySignals[0].SetSignal(OFX_EXIT_SIGNAL, OFX_SIGNAL_NONE); return(true); @@ -467,19 +427,39 @@ void CExpertBase::GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &r double sl = (mStopLossObj==NULL) ? mStopLossValue : mStopLossObj.GetStopLoss(); double tp = (mTakeProfitObj==NULL) ? mTakeProfitValue : mTakeProfitObj.GetTakeProfit(); + double sellPrice, buyPrice; + Trade.SetExpertMagicNumber(mMagicNumber); if(orderType==ORDER_TYPE_BUY) { - if(request.price==0.0) - request.price = SymbolInfoDouble(mSymbol, SYMBOL_ASK); + request.price = SymbolInfoDouble(mSymbol, SYMBOL_ASK); request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price+tp, mDigits); request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price-sl, mDigits); } if(orderType==ORDER_TYPE_SELL) { - if(request.price==0.0) - request.price = SymbolInfoDouble(mSymbol, SYMBOL_BID); + request.price = SymbolInfoDouble(mSymbol, SYMBOL_BID); + request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits); + request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits); + } + + if(orderType==ORDER_TYPE_SELL_STOP) + { + sellPrice = getLastSellOrderPrice()?getLastSellOrderPrice():getOpenedSellPositionPrice(); + sellPrice = (sellPrice==0.0)?SymbolInfoDouble(mSymbol, SYMBOL_BID):sellPrice; + + request.price = sellPrice-(mGridGap*_Point); + + request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits); + request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits); + } + + if(orderType==ORDER_TYPE_BUY_STOP) + { + buyPrice = getLastBuyOrderPrice()?getLastBuyOrderPrice():getOpenedBuyPositionPrice(); + buyPrice = (buyPrice==0.0)?SymbolInfoDouble(mSymbol, SYMBOL_ASK):buyPrice; + request.price = buyPrice+(mGridGap*_Point); request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits); request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits); } @@ -499,7 +479,7 @@ void CExpertBase::AddSignal(CSignalGrid *signal, CSignalGrid* &signals[]) } ////New -ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalGrid* &signals[], +/*ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalGrid* &signals[], ENUM_OFX_SIGNAL_TYPE signalType) { @@ -564,7 +544,7 @@ ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalGrid* &signals[] return(result); - } + }*/ //+------------------------------------------------------------------+ @@ -668,6 +648,10 @@ void CExpertBase::LotSize(double SL=0) } //+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ @@ -676,10 +660,24 @@ void CExpertBase::TradeWatcher(void) // Check the account balance equity for profit - int pCountBuy = 0, pCountSell = 0, oCountBuy = 0, oCountSell = 0, totalBuy = 0, totalSell = 0, realTotalBuy = 0, realTotalSell = 0; + int pCountBuy = 0, + pCountSell = 0, + oCountBuy = 0, + oCountSell = 0, + totalBuy = 0, + totalSell = 0, + realTotalBuy = 0, + realTotalSell = 0; int realOCountBuy, realOCountSell; + + lastBuyOrderPrice = 0.0; + lastSellOrderPrice = 0.0; + openedBuyPositionPrice = 0.0; + openedSellPositionPrice = 0.0; + ulong ticket; - signalDirection = NAV_SIGNAL_NONE; + entrySignal = OFX_SIGNAL_NONE; + exitSignal = OFX_SIGNAL_NONE; //If there're many positions and account balance is negative @@ -688,15 +686,21 @@ void CExpertBase::TradeWatcher(void) { //Count the opened positions by type int cntP = PositionsTotal(); + Print("cntP ", cntP-1); for(int i = cntP-1; i>=0; i--) { + Print(" i ", i); ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL)==mSymbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY && PositionGetInteger(POSITION_MAGIC)==mMagicNumber) { - openedBuyPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN); + if(pCountBuy == 0) + { + openedBuyPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN); + } + pCountBuy += 1; } @@ -704,7 +708,11 @@ void CExpertBase::TradeWatcher(void) if(PositionGetString(POSITION_SYMBOL)==mSymbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL && PositionGetInteger(POSITION_MAGIC)==mMagicNumber) { - openedSellPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN); + if(pCountSell == 0) + { + openedSellPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN); + } + pCountSell += 1; } } @@ -717,6 +725,7 @@ void CExpertBase::TradeWatcher(void) //Count the orders by type int cntO = OrdersTotal(); + Print("Total pending orders ", cntO); for(int i = cntO-1; i>=0; i--) { @@ -743,14 +752,12 @@ void CExpertBase::TradeWatcher(void) Print(GetLastError()); } } - Print("openedBuyPositionPrice ", openedBuyPositionPrice, " openedSellPositionPrice ", openedSellPositionPrice); - - Print("lastBuyOrderPrice ", lastBuyOrderPrice, " lastSellOrderPrice ", lastSellOrderPrice); double floatingProfitPercent = ((AccountInfoDouble(ACCOUNT_EQUITY) - AccountInfoDouble(ACCOUNT_BALANCE))*100)/AccountInfoDouble(ACCOUNT_BALANCE); +//mTargetProfit = AccountInfoDouble(ACCOUNT_BALANCE)*mProfitPercent/100; // Check if profit is at least the mMaxRiskPerTrade - Print(" MaxRiskPerTrade ",mMaxRiskPerTrade, " Floating profit percent ", floatingProfitPercent, " Account equity ", AccountInfoDouble(ACCOUNT_EQUITY), " Account balance ", AccountInfoDouble(ACCOUNT_BALANCE)); + Print(" Profit Percent ",mProfitPercent, " Floating profit percent ", floatingProfitPercent, " Account equity ", AccountInfoDouble(ACCOUNT_EQUITY), " Account balance ", AccountInfoDouble(ACCOUNT_BALANCE)); //The number of buy pending order should be twice the opened sell positions; and vice versa realOCountBuy = pCountSell+1; @@ -759,7 +766,7 @@ void CExpertBase::TradeWatcher(void) totalSell = pCountSell+oCountSell; realTotalBuy = pCountSell+1; realTotalSell = pCountBuy+1; - + Print("Sell order (", oCountSell, ") Real (", realOCountSell, ")"); Print("Buy order (", oCountBuy, ") Real (", realOCountBuy, ")", " Opened sell ", pCountSell); @@ -768,41 +775,54 @@ void CExpertBase::TradeWatcher(void) if(OrdersTotal() == 0 && PositionsTotal() == 0) { - signalDirection = NAV_SIGNAL_BOTH; + entrySignal = OFX_SIGNAL_BOTH; } + else { //If there's only one pending order left, close it. if(OrdersTotal() >= 1 && PositionsTotal() == 0) { - signalDirection = NAV_SIGNAL_ALL; + exitSignal = OFX_SIGNAL_ALL; Print("Exit if no opened position"); } + + else { - //When there are multiple positions, check is the account is making enough profit - if(floatingProfitPercent > mMaxRiskPerTrade) + //If there's only one pending order left, close it. + if(OrdersTotal() >= 1 && PositionsTotal() == 0) { - signalDirection = NAV_SIGNAL_ALL; - Print("Exit on profit target"); + exitSignal = OFX_SIGNAL_ALL; + Print("Exit if no opened position"); } else { - Print("realTotalSell ", realTotalSell, " <= ", " totalSell ", totalSell ," && ", " pCountBuy ",pCountBuy ," > 0"); - if(realTotalSell > totalSell && pCountBuy > 0) + //When there are multiple positions, check is the account is making enough profit + Print("floatingProfitPercent ", floatingProfitPercent, " mMaxRiskPerTrade ", mMaxRiskPerTrade); + if(floatingProfitPercent > mProfitPercent) { - signalType = NAV_ENTRY_SIGNAL; - signalDirection = NAV_SIGNAL_SELL; - Print("Sell order (", oCountSell, ") is less than it should be (", realOCountSell, ")"); + exitSignal = OFX_SIGNAL_ALL; + Print("Exit on profit target"); } else { - if(realTotalBuy > totalBuy && pCountSell > 0) + Print("realTotalSell ", realTotalSell, " <= ", " totalSell ", totalSell," && ", " pCountBuy ",pCountBuy," > 0"); + if(realTotalSell > totalSell && pCountBuy > 0) { - signalType = NAV_ENTRY_SIGNAL; - signalDirection = NAV_SIGNAL_BUY; - //mEntrySignals[0].SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_BUY); - Print("Buy order (", oCountBuy, ") is less than it should be (", realOCountBuy, ")"); + signalType = OFX_ENTRY_SIGNAL; + entrySignal = OFX_SIGNAL_SELL; + Print("Sell order (", oCountSell, ") is less than it should be (", realOCountSell, ")"); + } + else + { + if(realTotalBuy > totalBuy && pCountSell > 0) + { + signalType = OFX_ENTRY_SIGNAL; + entrySignal = OFX_SIGNAL_BUY; + //mEntrySignals[0].SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_BUY); + Print("Buy order (", oCountBuy, ") is less than it should be (", realOCountBuy, ")"); + } } } } @@ -810,3 +830,22 @@ void CExpertBase::TradeWatcher(void) } } //+------------------------------------------------------------------+ + +/*void CExpertBase::GetPendingOrderPrice(ENUM_OFX_SIGNAL_DIRECTION tradeType){ +if(tradeType == OFX_SIGNAL_BUY) + { + if(getLastBuyOrderPrice == 0.0) + { + pendingOrderPrice = openedBuyPositionPrice; + } else + { + if(condition) + { + + } + } + //buyPrice = (lastBuyOrderPrice == 0.0) ? openedBuyPositionPrice : lastBuyOrderPrice; + } +} +*/ +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/GDea/CheckHistory.mqh b/Include/Nkanven/GDea/CheckHistory.mqh new file mode 100644 index 0000000..8c5f1b0 --- /dev/null +++ b/Include/Nkanven/GDea/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/GDea/ClosePositions.mqh b/Include/Nkanven/GDea/ClosePositions.mqh new file mode 100644 index 0000000..219a413 --- /dev/null +++ b/Include/Nkanven/GDea/ClosePositions.mqh @@ -0,0 +1,38 @@ +//+------------------------------------------------------------------+ +//| ClosePositions.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; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool OrderClose() + { + bool result = true; + int cnt = OrdersTotal(); + if(cnt == 1) + { + + + for(int i = cnt-1; i>=0; i--) + { + ulong ticket = OrderGetTicket(i); + if(OrderSelect(ticket)) + { + + result &= trade.OrderDelete(ticket); + } + else + { + result = false; + } + } + } + return(result); + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/GDea/EntriesManager.mqh b/Include/Nkanven/GDea/EntriesManager.mqh new file mode 100644 index 0000000..23c319f Binary files /dev/null and b/Include/Nkanven/GDea/EntriesManager.mqh differ diff --git a/Include/Nkanven/GDea/LotSizeCal.mqh b/Include/Nkanven/GDea/LotSizeCal.mqh new file mode 100644 index 0000000..4d4ba0f --- /dev/null +++ b/Include/Nkanven/GDea/LotSizeCal.mqh @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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; + double RiskBase=0; + + //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(RiskBase==RISK_BASE_BALANCE) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE); + if(RiskBase==RISK_BASE_EQUITY) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY); + if(RiskBase==RISK_BASE_FREEMARGIN) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN); + + //Calculate the Position Size + LotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue)); + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>InpMaxLotSize) + LotSize=InpMaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX); + Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSizeInpMaxStopLoss) + { + 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; + } + } diff --git a/Include/Nkanven/GDea/ScanPositions.mqh b/Include/Nkanven/GDea/ScanPositions.mqh new file mode 100644 index 0000000..9125ec1 --- /dev/null +++ b/Include/Nkanven/GDea/ScanPositions.mqh @@ -0,0 +1,51 @@ +//+------------------------------------------------------------------+ +//| 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 +bool ScanPositions() + { + +//Scan all the orders, retrieving some of the details + gTotalOpenOrders = 0; + gTotalOpenBuy = 0; + gTotalOpenSell = 0; + for(int i=0; igLastBarTraded || gLastBarTraded==NULL) + gLastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); + } + Print("Total positions ", gTotalOpenOrders, " - Total buys ", gTotalOpenBuy, " - Total sells ", gTotalOpenSell); + return true; + } \ No newline at end of file diff --git a/Include/Nkanven/GDea/TradeManager.mqh b/Include/Nkanven/GDea/TradeManager.mqh new file mode 100644 index 0000000..3bf43bd --- /dev/null +++ b/Include/Nkanven/GDea/TradeManager.mqh @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| TradeManager.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/GDea/TradingHour.mqh b/Include/Nkanven/GDea/TradingHour.mqh new file mode 100644 index 0000000..249ec7b --- /dev/null +++ b/Include/Nkanven/GDea/TradingHour.mqh @@ -0,0 +1,48 @@ +//+------------------------------------------------------------------+ +//| TradingHour.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +//Check and return if it is operation hours or not +void CheckOperationHours() + { +//If we are not using operating hours then IsOperatingHours is true and I skip the other checks + if(!InpUseTradingHours) + { + gIsOperatingHours=true; + return; + } +//Check if the current hour is between the allowed hours of operations, if so IsOperatingHours is set true + Print("1 this is ", (InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart)); + + if(InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart) + { + gIsOperatingHours=true; + return; + } + + if(InpTradingHourStart= InpTradingStartMin) + { + gIsOperatingHours=true; + return; + } + if(dt.hour > InpTradingHourStart && dt.hour < InpTradingHourEnd) + { + gIsOperatingHours=true; + } + + + } + + if(InpTradingHourStart>InpTradingHourEnd && ((dt.hour>=InpTradingHourStart && dt.hour<=23) || (dt.hour<=InpTradingHourEnd && dt.hour>=0))) + { + gIsOperatingHours=true; + } + + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/GeminiHedge/CheckHistory.mqh b/Include/Nkanven/GeminiHedge/CheckHistory.mqh new file mode 100644 index 0000000..8c5f1b0 --- /dev/null +++ b/Include/Nkanven/GeminiHedge/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/GeminiHedge/CloseTransactions.mqh b/Include/Nkanven/GeminiHedge/CloseTransactions.mqh new file mode 100644 index 0000000..e69de29 diff --git a/Include/Nkanven/GeminiHedge/DCAManager.mqh b/Include/Nkanven/GeminiHedge/DCAManager.mqh new file mode 100644 index 0000000..bb6ad54 --- /dev/null +++ b/Include/Nkanven/GeminiHedge/DCAManager.mqh @@ -0,0 +1,133 @@ +//+------------------------------------------------------------------+ +//| DCAManager.mqh | +//| Copyright 2022, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, MetaQuotes Ltd." +#property link "https://www.mql5.com" + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void DcaManager() + { +//Compute pending orders levels + ENUM_DCA_STATUS dcaStatus = DcaWatcher(); + + switch(dcaStatus) + { + case NO_DEALS : + signal = NO_SIGNAL; + break; + case NO_BUY_POSITIONS : + signal = BUY_SIGNAL; + break; + case BUY_PENDING_ORDERS : + signal = PENDING_ORDERS; + break; + case NO_UPPER_BUY_ORDER : + signal = BUY_STOP_SIGNAL; + break; + case NO_LOWER_BUY_ORDER : + signal = BUY_LIMIT_SIGNAL; + break; + case BUY_POSITION_EXISTS : + signal = NO_SIGNAL; + break; + default: + signal = NO_SIGNAL; + break; + } + + + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +ENUM_DCA_STATUS DcaWatcher() + { + if(gTotalBuyPositions > 0) + { + bool hasOrderAbove = false, hasOrderBelow = false; + + if(PositionGetTicket(lastTicketId) == 0) + { + int Error=GetLastError(); + Print("ERROR - Unable to select the position - ",Error," - ",Error); + return NO_DEALS; + } + if(PositionSelect(gSymbol)) + { + if(PositionGetSymbol(lastTicketId)==gSymbol && PositionGetInteger(POSITION_MAGIC)==InpMagicNumber) + { + //Compute above and below orders price + Print("Last ticket id ", lastTicketId, " last ticket price ", PositionGetDouble(POSITION_PRICE_OPEN)); + gUpOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN) + (InpBuyCallBack * point); + gDownOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN) - (InpBuyCallBack * point); + + Print("gUpOpenPrice ", gUpOpenPrice, " gDownOpenPrice ", gDownOpenPrice); + + //Check orders around the last opened position + for(int i=0; iSymbolInfoDouble(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/GeminiHedge/ScanPositions.mqh b/Include/Nkanven/GeminiHedge/ScanPositions.mqh new file mode 100644 index 0000000..303d323 --- /dev/null +++ b/Include/Nkanven/GeminiHedge/ScanPositions.mqh @@ -0,0 +1,74 @@ +//+------------------------------------------------------------------+ +//| ScanPositions.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.linkedin.com/in/nkondog | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.linkedin.com/in/nkondog" + +//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(); + gTotalOrders = OrdersTotal(); + gTotalBuyPositions = 0; + gTotalBuyOrders = 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; + } + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Gervis/CheckHistory.mqh b/Include/Nkanven/Gervis/CheckHistory.mqh new file mode 100644 index 0000000..8c5f1b0 --- /dev/null +++ b/Include/Nkanven/Gervis/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/Gervis/ClosePositions.mqh b/Include/Nkanven/Gervis/ClosePositions.mqh new file mode 100644 index 0000000..219a413 --- /dev/null +++ b/Include/Nkanven/Gervis/ClosePositions.mqh @@ -0,0 +1,38 @@ +//+------------------------------------------------------------------+ +//| ClosePositions.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; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool OrderClose() + { + bool result = true; + int cnt = OrdersTotal(); + if(cnt == 1) + { + + + for(int i = cnt-1; i>=0; i--) + { + ulong ticket = OrderGetTicket(i); + if(OrderSelect(ticket)) + { + + result &= trade.OrderDelete(ticket); + } + else + { + result = false; + } + } + } + return(result); + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Gervis/EntriesManager.mqh b/Include/Nkanven/Gervis/EntriesManager.mqh new file mode 100644 index 0000000..9e58a69 Binary files /dev/null and b/Include/Nkanven/Gervis/EntriesManager.mqh differ diff --git a/Include/Nkanven/Gervis/EntriesManagerDCA.mqh b/Include/Nkanven/Gervis/EntriesManagerDCA.mqh new file mode 100644 index 0000000..dd503b1 Binary files /dev/null and b/Include/Nkanven/Gervis/EntriesManagerDCA.mqh differ diff --git a/Include/Nkanven/Gervis/HighestPriceLevel.mqh b/Include/Nkanven/Gervis/HighestPriceLevel.mqh new file mode 100644 index 0000000..bb464e6 --- /dev/null +++ b/Include/Nkanven/Gervis/HighestPriceLevel.mqh @@ -0,0 +1,33 @@ +//+------------------------------------------------------------------+ +//| HighestPriceLevel.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void drawLine() + { + string obj_name = "Recent high"; + + if(highestPrice != gLastHighestPrice) + { + ObjectDelete(current_chart_id, obj_name); + } + ObjectCreate(current_chart_id, obj_name, OBJ_HLINE, 0, iTime(gSymbol,_Period,0), gLastHighestPrice); + +//--- set color to Red + ObjectSetInteger(current_chart_id, obj_name, OBJPROP_COLOR, clrRed); +//--- set object width + ObjectSetInteger(current_chart_id, obj_name, OBJPROP_WIDTH, 1); +//--- Move the line + ObjectMove(current_chart_id, obj_name, 0, iTime(gSymbol,_Period,0), gLastHighestPrice); + + highestPrice = gLastHighestPrice; + + Print("Drawing line"); + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Gervis/LotSizeCal.mqh b/Include/Nkanven/Gervis/LotSizeCal.mqh new file mode 100644 index 0000000..2fafb5b --- /dev/null +++ b/Include/Nkanven/Gervis/LotSizeCal.mqh @@ -0,0 +1,59 @@ +//+------------------------------------------------------------------+ +//| 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; + double RiskBase=0; + + //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(RiskBase==RISK_BASE_BALANCE) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE); + if(RiskBase==RISK_BASE_EQUITY) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY); + if(RiskBase==RISK_BASE_FREEMARGIN) + RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN); + + //Calculate the Position Size + LotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue)); + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP); + + printf("Lot size ", LotSize); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>InpMaxLotSize) + LotSize=InpMaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX); + Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSizeInpMaxStopLoss) + { + 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; + } + } diff --git a/Include/Nkanven/Gervis/ScanPositions.mqh b/Include/Nkanven/Gervis/ScanPositions.mqh new file mode 100644 index 0000000..7adfdb0 --- /dev/null +++ b/Include/Nkanven/Gervis/ScanPositions.mqh @@ -0,0 +1,49 @@ +//+------------------------------------------------------------------+ +//| 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 +bool ScanPositions() + { + +//Scan all the orders, retrieving some of the details + gTotalOpenOrders = 0; + gTotalOpenBuy = 0; + gTotalOpenSell = 0; + for(int i=0; igLastBarTraded || gLastBarTraded==NULL) + gLastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); + } + Print("Total positions ", gTotalOpenOrders, " - Total buys ", gTotalOpenBuy, " - Total sells ", gTotalOpenSell); + return true; + } \ No newline at end of file diff --git a/Include/Nkanven/Gervis/TradeManager.mqh b/Include/Nkanven/Gervis/TradeManager.mqh new file mode 100644 index 0000000..3bf43bd --- /dev/null +++ b/Include/Nkanven/Gervis/TradeManager.mqh @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| TradeManager.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/Gervis/TradingHour.mqh b/Include/Nkanven/Gervis/TradingHour.mqh new file mode 100644 index 0000000..945f776 --- /dev/null +++ b/Include/Nkanven/Gervis/TradingHour.mqh @@ -0,0 +1,49 @@ +//+------------------------------------------------------------------+ +//| TradingHour.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +//Check and return if it is operation hours or not +void CheckOperationHours() + { +//If we are not using operating hours then IsOperatingHours is true and I skip the other checks + if(!InpUseTradingHours) + { + gIsOperatingHours=true; + return; + } +//Check if the current hour is between the allowed hours of operations, if so IsOperatingHours is set true + Print("1 this is ", (InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart)); + Print("2 this is ", (InpTradingHourStart= InpTradingStartMin); + + if(InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart) + { + gIsOperatingHours=true; + return; + } + + if(InpTradingHourStart= InpTradingStartMin) + { + gIsOperatingHours=true; + return; + } + if(dt.hour > InpTradingHourStart) + { + gIsOperatingHours=true; + return; + } + } + + if(InpTradingHourStart>InpTradingHourEnd && ((dt.hour>=InpTradingHourStart && dt.hour<=23) || (dt.hour<=InpTradingHourEnd && dt.hour>=0))) + { + gIsOperatingHours=true; + return; + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/HighTension/CheckHistory.mqh b/Include/Nkanven/HighTension/CheckHistory.mqh new file mode 100644 index 0000000..8c5f1b0 --- /dev/null +++ b/Include/Nkanven/HighTension/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/HighTension/CloseTransactions.mqh b/Include/Nkanven/HighTension/CloseTransactions.mqh new file mode 100644 index 0000000..5803a7e --- /dev/null +++ b/Include/Nkanven/HighTension/CloseTransactions.mqh @@ -0,0 +1,50 @@ +//+------------------------------------------------------------------+ +//| 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(); + + if(cts > 0) + { + for(int i = cts-1; i>=0; i--) + { + ulong ticket = PositionGetTicket(i); + if(PositionSelectByTicket(ticket)) + { + if(PositionGetInteger(POSITION_MAGIC)==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && currentColor == 1.0) + { + if(!trade.PositionClose(ticket)) + Print("Error (", GetLastError(), ") while deleting all buy positions"); + } + + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && currentColor == 0.0) + { + if(!trade.PositionClose(ticket)) + Print("Error (", GetLastError(), ") while deleting all buy positions"); + } + } + } + else + { + Print("Error (", GetLastError(), ") while selecting position by ticket"); + } + } + } + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/HighTension/EntriesManager.mqh b/Include/Nkanven/HighTension/EntriesManager.mqh new file mode 100644 index 0000000..f2b6660 Binary files /dev/null and b/Include/Nkanven/HighTension/EntriesManager.mqh differ diff --git a/Include/Nkanven/HighTension/LotSizeCal.mqh b/Include/Nkanven/HighTension/LotSizeCal.mqh new file mode 100644 index 0000000..7bf44fc --- /dev/null +++ b/Include/Nkanven/HighTension/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 + Spread = (last_tick.ask-last_tick.bid)/Point(); + if(Spread>InpMaxSpread) + { + gIsPreChecksOk=false; + Print("Spread is higher than Max acceptable spread"); + return; + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/HighTension/ScanPositions.mqh b/Include/Nkanven/HighTension/ScanPositions.mqh new file mode 100644 index 0000000..e3316cc --- /dev/null +++ b/Include/Nkanven/HighTension/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 0) + { + + + for(int i = cnt-1; i>=0; i--) + { + ulong ticket = OrderGetTicket(i); + if(OrderSelect(ticket)) + { + if(tType==SIGNAL_EXIT_BUY && (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_LIMIT || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) && OrderGetInteger(ORDER_MAGIC)==InpMagicNumber) + { + if(!trade.OrderDelete(ticket)) + Print("Error (", GetLastError(), ") while deleting all buy orders"); + } + else + { + if(tType==SIGNAL_EXIT_SELL && (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP) && OrderGetInteger(ORDER_MAGIC)==InpMagicNumber) + { + if(!trade.OrderDelete(ticket)) + Print("Error (", GetLastError(), ") while deleting all sell orders"); + } + else + { + if(tType==SIGNAL_EXIT_ALL) + { + if(!trade.OrderDelete(ticket)) + Print("Error (", GetLastError(), ") while deleting all orders"); + } + } + } + } + else + { + Print("Error (", GetLastError(), ") while selecting order's ticket"); + } + } + } + + if(cts > 0) + { + for(int i = cts-1; i>=0; i--) + { + ulong ticket = PositionGetTicket(i); + if(PositionSelectByTicket(ticket)) + { + if(tType==SIGNAL_EXIT_BUY && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && PositionGetInteger(POSITION_MAGIC)==InpMagicNumber) + { + if(!trade.PositionClose(ticket)) + Print("Error (", GetLastError(), ") while deleting all buy positions"); + } + else + { + if(tType==SIGNAL_EXIT_SELL && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && PositionGetInteger(POSITION_MAGIC)==InpMagicNumber) + { + if(!trade.PositionClose(ticket)) + Print("Error (", GetLastError(), ") while deleting all sell positions"); + } + else + { + if(tType==SIGNAL_EXIT_ALL) + { + if(!trade.PositionClose(ticket)) + Print("Error (", GetLastError(), ") while deleting all positions"); + } + } + } + + } + else + { + Print("Error (", GetLastError(), ") while selecting position by ticket"); + } + } + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/MAGrid/EntriesManager.mqh b/Include/Nkanven/MAGrid/EntriesManager.mqh new file mode 100644 index 0000000..2288fa9 Binary files /dev/null and b/Include/Nkanven/MAGrid/EntriesManager.mqh differ diff --git a/Include/Nkanven/MAGrid/LotSizeCal.mqh b/Include/Nkanven/MAGrid/LotSizeCal.mqh new file mode 100644 index 0000000..5ff8fc3 --- /dev/null +++ b/Include/Nkanven/MAGrid/LotSizeCal.mqh @@ -0,0 +1,56 @@ +//+------------------------------------------------------------------+ +//| 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; + + //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 + LotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue)); + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>InpMaxLotSize) + LotSize=InpMaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX); + Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSizeInpMaxStopLoss) + { + 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; + } + } diff --git a/Include/Nkanven/MAGrid/ScanPositions.mqh b/Include/Nkanven/MAGrid/ScanPositions.mqh new file mode 100644 index 0000000..dd7052e --- /dev/null +++ b/Include/Nkanven/MAGrid/ScanPositions.mqh @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| 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 +bool ScanPositions() + { + +//Scan all the orders, retrieving some of the details + gTotalOpenOrders = OrdersTotal(); + gTotalPositions = PositionsTotal(); + gTotalBuyPositions = 0; + gTotalSellPositions = 0; + gTotalTransactions = gTotalOpenOrders+gTotalPositions; + + for(int i=0; igLastBarTraded || gLastBarTraded==NULL) + gLastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); + } + Print("Total positions ", gTotalPositions, " - Total buys ", gTotalBuyPositions, " - Total sells ", gTotalSellPositions); + return true; + } \ No newline at end of file diff --git a/Include/Nkanven/MAGrid/TradeManager.mqh b/Include/Nkanven/MAGrid/TradeManager.mqh new file mode 100644 index 0000000..3bf43bd --- /dev/null +++ b/Include/Nkanven/MAGrid/TradeManager.mqh @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| TradeManager.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/MAGrid/TradingHour.mqh b/Include/Nkanven/MAGrid/TradingHour.mqh new file mode 100644 index 0000000..7933ad8 --- /dev/null +++ b/Include/Nkanven/MAGrid/TradingHour.mqh @@ -0,0 +1,45 @@ +//+------------------------------------------------------------------+ +//| TradingHour.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +//Check and return if it is operation hours or not +void CheckOperationHours() + { +//If we are not using operating hours then IsOperatingHours is true and I skip the other checks + if(!InpUseTradingHours) + { + gIsOperatingHours=true; + return; + } +//Check if the current hour is between the allowed hours of operations, if so IsOperatingHours is set true + Print("1 this is ", (InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart)); + + if(InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart) + { + gIsOperatingHours=true; + return; + } + + if(InpTradingHourStart= InpTradingStartMin) + { + gIsOperatingHours=true; + return; + } + if(dt.hour > InpTradingHourStart) + { + gIsOperatingHours=true; + } + } + + if(InpTradingHourStart>InpTradingHourEnd && ((dt.hour>=InpTradingHourStart && dt.hour<=23) || (dt.hour<=InpTradingHourEnd && dt.hour>=0))) + { + gIsOperatingHours=true; + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/MidNightAngel/CheckHistory.mqh b/Include/Nkanven/MidNightAngel/CheckHistory.mqh new file mode 100644 index 0000000..8c5f1b0 --- /dev/null +++ b/Include/Nkanven/MidNightAngel/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/MidNightAngel/CloseTransactions.mqh b/Include/Nkanven/MidNightAngel/CloseTransactions.mqh new file mode 100644 index 0000000..ed3bd1b --- /dev/null +++ b/Include/Nkanven/MidNightAngel/CloseTransactions.mqh @@ -0,0 +1,94 @@ +//+------------------------------------------------------------------+ +//| 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(ENUM_SIGNAL_EXIT tType) + { + bool result = true; + int cnt = OrdersTotal(); + int cts = PositionsTotal(); + if(cnt > 0) + { + + + for(int i = cnt-1; i>=0; i--) + { + ulong ticket = OrderGetTicket(i); + if(OrderSelect(ticket)) + { + if(tType==SIGNAL_EXIT_BUY && (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_LIMIT || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) && OrderGetInteger(ORDER_MAGIC)==InpMagicNumber) + { + if(!trade.OrderDelete(ticket)) + Print("Error (", GetLastError(), ") while deleting all buy orders"); + } + else + { + if(tType==SIGNAL_EXIT_SELL && (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP) && OrderGetInteger(ORDER_MAGIC)==InpMagicNumber) + { + if(!trade.OrderDelete(ticket)) + Print("Error (", GetLastError(), ") while deleting all sell orders"); + } + else + { + if(tType==SIGNAL_EXIT_ALL) + { + if(!trade.OrderDelete(ticket)) + Print("Error (", GetLastError(), ") while deleting all orders"); + } + } + } + } + else + { + Print("Error (", GetLastError(), ") while selecting order's ticket"); + } + } + } + + if(cts > 0) + { + for(int i = cts-1; i>=0; i--) + { + ulong ticket = PositionGetTicket(i); + if(PositionSelectByTicket(ticket)) + { + if(tType==SIGNAL_EXIT_BUY && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && PositionGetInteger(POSITION_MAGIC)==InpMagicNumber) + { + if(!trade.PositionClose(ticket)) + Print("Error (", GetLastError(), ") while deleting all buy positions"); + } + else + { + if(tType==SIGNAL_EXIT_SELL && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && PositionGetInteger(POSITION_MAGIC)==InpMagicNumber) + { + if(!trade.PositionClose(ticket)) + Print("Error (", GetLastError(), ") while deleting all sell positions"); + } + else + { + if(tType==SIGNAL_EXIT_ALL) + { + if(!trade.PositionClose(ticket)) + Print("Error (", GetLastError(), ") while deleting all positions"); + } + } + } + + } + else + { + Print("Error (", GetLastError(), ") while selecting position by ticket"); + } + } + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/MidNightAngel/EntriesManager.mqh b/Include/Nkanven/MidNightAngel/EntriesManager.mqh new file mode 100644 index 0000000..2288fa9 Binary files /dev/null and b/Include/Nkanven/MidNightAngel/EntriesManager.mqh differ diff --git a/Include/Nkanven/MidNightAngel/LotSizeCal.mqh b/Include/Nkanven/MidNightAngel/LotSizeCal.mqh new file mode 100644 index 0000000..5ff8fc3 --- /dev/null +++ b/Include/Nkanven/MidNightAngel/LotSizeCal.mqh @@ -0,0 +1,56 @@ +//+------------------------------------------------------------------+ +//| 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; + + //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 + LotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue)); + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>InpMaxLotSize) + LotSize=InpMaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX); + Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSizeInpMaxStopLoss) + { + 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; + } + } diff --git a/Include/Nkanven/MidNightAngel/ScanPositions.mqh b/Include/Nkanven/MidNightAngel/ScanPositions.mqh new file mode 100644 index 0000000..dd7052e --- /dev/null +++ b/Include/Nkanven/MidNightAngel/ScanPositions.mqh @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| 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 +bool ScanPositions() + { + +//Scan all the orders, retrieving some of the details + gTotalOpenOrders = OrdersTotal(); + gTotalPositions = PositionsTotal(); + gTotalBuyPositions = 0; + gTotalSellPositions = 0; + gTotalTransactions = gTotalOpenOrders+gTotalPositions; + + for(int i=0; igLastBarTraded || gLastBarTraded==NULL) + gLastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); + } + Print("Total positions ", gTotalPositions, " - Total buys ", gTotalBuyPositions, " - Total sells ", gTotalSellPositions); + return true; + } \ No newline at end of file diff --git a/Include/Nkanven/MidNightAngel/TradeManager.mqh b/Include/Nkanven/MidNightAngel/TradeManager.mqh new file mode 100644 index 0000000..3bf43bd --- /dev/null +++ b/Include/Nkanven/MidNightAngel/TradeManager.mqh @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| TradeManager.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/MidNightAngel/TradingHour.mqh b/Include/Nkanven/MidNightAngel/TradingHour.mqh new file mode 100644 index 0000000..7933ad8 --- /dev/null +++ b/Include/Nkanven/MidNightAngel/TradingHour.mqh @@ -0,0 +1,45 @@ +//+------------------------------------------------------------------+ +//| TradingHour.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +//Check and return if it is operation hours or not +void CheckOperationHours() + { +//If we are not using operating hours then IsOperatingHours is true and I skip the other checks + if(!InpUseTradingHours) + { + gIsOperatingHours=true; + return; + } +//Check if the current hour is between the allowed hours of operations, if so IsOperatingHours is set true + Print("1 this is ", (InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart)); + + if(InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart) + { + gIsOperatingHours=true; + return; + } + + if(InpTradingHourStart= InpTradingStartMin) + { + gIsOperatingHours=true; + return; + } + if(dt.hour > InpTradingHourStart) + { + gIsOperatingHours=true; + } + } + + if(InpTradingHourStart>InpTradingHourEnd && ((dt.hour>=InpTradingHourStart && dt.hour<=23) || (dt.hour<=InpTradingHourEnd && dt.hour>=0))) + { + gIsOperatingHours=true; + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/NYMidnightBreak/Functions.mqh b/Include/Nkanven/NYMidnightBreak/Functions.mqh new file mode 100644 index 0000000..30ec714 --- /dev/null +++ b/Include/Nkanven/NYMidnightBreak/Functions.mqh @@ -0,0 +1,30 @@ +//+------------------------------------------------------------------+ +//| Functions.mqh | +//| Copyright 2022, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, MetaQuotes Ltd." +#property link "https://www.mql5.com" + + +//Check and return if the spread is not too high +void CheckSpread() + { +//Get the current spread in points, the (int) transforms the double coming from MarketInfo into an integer to avoid a warning when compiling + long SpreadCurr=(int)Spread; + Print("Spread ", Spread); + if(SpreadCurr<=InpMaxSpread) + { + IsSpreadOK=true; + } + else + { + IsSpreadOK=false; + } + } + +double GetSignalBoundries() +{ + //Get midnight high and low + iHigh() +} \ No newline at end of file diff --git a/Include/Nkanven/NYMidnightBreak/LotSizeCal.mqh b/Include/Nkanven/NYMidnightBreak/LotSizeCal.mqh new file mode 100644 index 0000000..5ff8fc3 --- /dev/null +++ b/Include/Nkanven/NYMidnightBreak/LotSizeCal.mqh @@ -0,0 +1,56 @@ +//+------------------------------------------------------------------+ +//| 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; + + //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 + LotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue)); + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>InpMaxLotSize) + LotSize=InpMaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX); + Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSize 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/TheChallenger/EntriesManager.mqh b/Include/Nkanven/TheChallenger/EntriesManager.mqh new file mode 100644 index 0000000..0651068 Binary files /dev/null and b/Include/Nkanven/TheChallenger/EntriesManager.mqh differ diff --git a/Include/Nkanven/TheChallenger/LotSizeCal.mqh b/Include/Nkanven/TheChallenger/LotSizeCal.mqh new file mode 100644 index 0000000..7bf44fc --- /dev/null +++ b/Include/Nkanven/TheChallenger/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/TheChallenger/ScanPositions.mqh b/Include/Nkanven/TheChallenger/ScanPositions.mqh new file mode 100644 index 0000000..02076cf --- /dev/null +++ b/Include/Nkanven/TheChallenger/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; + } + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/logger.mqh b/Include/Nkanven/logger.mqh new file mode 100644 index 0000000..1868d2a Binary files /dev/null and b/Include/Nkanven/logger.mqh differ diff --git a/LotCal - Copy.mq4 b/LotCal - Copy.mq4 new file mode 100644 index 0000000..8d2e4cd --- /dev/null +++ b/LotCal - Copy.mq4 @@ -0,0 +1,172 @@ +//+------------------------------------------------------------------+ +//| LotCal.mq4 | +//| Copyright 2022, Nkondog Anselme Venceslas. | +//| https://www.linkedin/in/nkondog.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, Nkondog Anselme Venceslas." +#property link "https://www.linkedin/in/nkondog.com " +#property version "1.00" +#property strict + +//Parameters + +//Enumerative for the base used for risk calculation +enum ENUM_RISK_BASE + { + RISK_BASE_EQUITY=1, //EQUITY + RISK_BASE_BALANCE=2, //BALANCE + RISK_BASE_FREEMARGIN=3, //FREE MARGIN + RISK_BASE_INPUT=4, //INPUT BASE + }; + +//Enumerative for the default risk size +enum ENUM_RISK_DEFAULT_SIZE + { + RISK_DEFAULT_FIXED=1, //FIXED SIZE + RISK_DEFAULT_AUTO=2, //AUTOMATIC SIZE BASED ON RISK + }; + +input ENUM_RISK_DEFAULT_SIZE InpRiskDefaultSize=RISK_DEFAULT_AUTO; //Position Size Mode +input double InpBalance=10000.0; //Balance +input double InpDefaultLotSize=0.01; //Position Size (if fixed or if no stop loss defined) +input ENUM_RISK_BASE InpRiskBase=RISK_BASE_BALANCE; //Risk Base +input double InpMaxRiskPerTrade=0.5; //Percentage To Risk Each Trade +input double InpMinLotSize=0.01; //Minimum Position Size Allowed +input double InpMaxLotSize=100; //Maximum Position Size Allowedv + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string Symb = Symbol(); +double LotSize=InpDefaultLotSize; +double price=0.0; +double risk=0.0; +double StoplossPips=0.0; +//TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty +double TickValue=SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_VALUE); + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + Print("The Expert Advisor with name ",MQLInfoString(MQL_PROGRAM_NAME)," is running"); +//--- enable object create events + ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true); +//--- enable object delete events + ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true); +//--- + return(INIT_SUCCEEDED); + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void OnTick() + { + LotSizeCalculate(price); +//Comment("Lot size : ", LotSize); +double StopAmount = StoplossPips * LotSize * TickValue; + string text ="Lot size for "+ InpMaxRiskPerTrade +"% = " + DoubleToString(LotSize,2) + " lot (" + DoubleToString(StopAmount, 2) + " " + AccountInfoString(ACCOUNT_CURRENCY) + ")"; + string name = "Lot"; + ObjectCreate(name, OBJ_LABEL, 0, 0, 0); + ObjectSetText(name,text, 14, "Corbel Bold", YellowGreen); + ObjectSet(name, OBJPROP_CORNER, CORNER_RIGHT_UPPER); + ObjectSet(name, OBJPROP_XDISTANCE, 350); + ObjectSet(name, OBJPROP_YDISTANCE, 10); + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, // Event identifier + const long& lparam, // Event parameter of long type + const double& dparam, // Event parameter of double type + const string& sparam) // Event parameter of string type + { +//--- the object has been deleted + if(id==CHARTEVENT_OBJECT_DELETE) + { + Print("The object with name ",sparam," has been deleted"); + } +//--- the object has been created + if(id==CHARTEVENT_OBJECT_CREATE) + { + Print("The object with name ",sparam," has been created"); + } + +//--- the object has been moved or its anchor point coordinates has been changed + if(id==CHARTEVENT_OBJECT_DRAG) + { + price = ObjectGetDouble(0, sparam, OBJPROP_PRICE, 0); + Print("The anchor point coordinates of the object with name ",sparam," has been changed. Price ", price); + } + } + + +//Lot Size Calculator +void LotSizeCalculate(double stopLoss) + { + double SL=0; + double PriceAsk=MarketInfo(0,MODE_ASK); + double PriceBid=MarketInfo(0,MODE_BID); + + if(stopLoss < PriceAsk) + { + SL = (PriceAsk-stopLoss)/_Point; + } + if(stopLoss > PriceAsk) + { + SL = (stopLoss-PriceBid)/_Point; + } + Print("Stop loss distance ", SL); + +//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; + //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); + if(InpRiskBase==RISK_BASE_INPUT) + RiskBaseAmount=InpBalance; + + //Calculate the Position Size + Print("RiskBaseAmount ", RiskBaseAmount, " MaxRiskPerTrade ", InpMaxRiskPerTrade, "Stop loss ", SL, " TickValue ", TickValue); + + LotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue)); + StoplossPips = SL; + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>InpMaxLotSize) + LotSize=InpMaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX); + Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSize < SymbolInfoDouble(Symb,SYMBOL_VOLUME_MIN)) + { + LotSize=0; + Print("Lot size too small"); + } + } +//+------------------------------------------------------------------+ diff --git a/LotCal.ex4 b/LotCal.ex4 new file mode 100644 index 0000000..643cf08 Binary files /dev/null and b/LotCal.ex4 differ diff --git a/LotCal.mq4 b/LotCal.mq4 new file mode 100644 index 0000000..411d9ce --- /dev/null +++ b/LotCal.mq4 @@ -0,0 +1,211 @@ +//+------------------------------------------------------------------+ +//| LotCal.mq4 | +//| Copyright 2022, Nkondog Anselme Venceslas. | +//| https://www.linkedin/in/nkondog.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, Nkondog Anselme Venceslas." +#property link "https://www.linkedin/in/nkondog.com " +#property version "1.00" +#property strict + +#define KEY_B 66 +#define KEY_S 83 + +//Parameters + +//Enumerative for the base used for risk calculation +enum ENUM_RISK_BASE + { + RISK_BASE_EQUITY=1, //EQUITY + RISK_BASE_BALANCE=2, //BALANCE + RISK_BASE_FREEMARGIN=3, //FREE MARGIN + RISK_BASE_INPUT=4, //INPUT BASE + }; + +//Enumerative for the default risk size +enum ENUM_RISK_DEFAULT_SIZE + { + RISK_DEFAULT_FIXED=1, //FIXED SIZE + RISK_DEFAULT_AUTO=2, //AUTOMATIC SIZE BASED ON RISK + }; + +input ENUM_RISK_DEFAULT_SIZE InpRiskDefaultSize=RISK_DEFAULT_AUTO; //Position Size Mode +input double InpBalance=10000.0; //Balance +input double InpDefaultLotSize=0.01; //Position Size (if fixed or if no stop loss defined) +input ENUM_RISK_BASE InpRiskBase=RISK_BASE_BALANCE; //Risk Base +input double InpMaxRiskPerTrade=0.5; //Percentage To Risk Each Trade +input double InpMinLotSize=0.01; //Minimum Position Size Allowed +input double InpMaxLotSize=100; //Maximum Position Size Allowedv + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string Symb = Symbol(); +double LotSize=InpDefaultLotSize; +double price=0.0; +double risk=0.0; +double StoplossPips=0.0; +//TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty +double TickValue=SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_VALUE); +int ticket; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + Print("The Expert Advisor with name ",MQLInfoString(MQL_PROGRAM_NAME)," is running"); +//--- enable object create events + ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true); +//--- enable object delete events + ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true); +//--- + return(INIT_SUCCEEDED); + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void OnTick() + { + LotSizeCalculate(price); +//Comment("Lot size : ", LotSize); +double StopAmount = StoplossPips * LotSize * TickValue; + string text ="Lot size for "+ InpMaxRiskPerTrade +"% = " + DoubleToString(LotSize,2) + " lot (" + DoubleToString(StopAmount, 2) + " " + AccountInfoString(ACCOUNT_CURRENCY) + ")"; + string name = "Lot"; + ObjectCreate(name, OBJ_LABEL, 0, 0, 0); + ObjectSetText(name,text, 14, "Corbel Bold", YellowGreen); + ObjectSet(name, OBJPROP_CORNER, CORNER_RIGHT_UPPER); + ObjectSet(name, OBJPROP_XDISTANCE, 350); + ObjectSet(name, OBJPROP_YDISTANCE, 10); + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, // Event identifier + const long& lparam, // Event parameter of long type + const double& dparam, // Event parameter of double type + const string& sparam) // Event parameter of string type + { +//--- the object has been deleted + if(id==CHARTEVENT_OBJECT_DELETE) + { + Print("The object with name ",sparam," has been deleted"); + } +//--- the object has been created + if(id==CHARTEVENT_OBJECT_CREATE) + { + Print("The object with name ",sparam," has been created"); + } + +//--- the object has been moved or its anchor point coordinates has been changed + if(id==CHARTEVENT_OBJECT_DRAG) + { + price = ObjectGetDouble(0, sparam, OBJPROP_PRICE, 0); + ///Print("The anchor point coordinates of the object with name ",sparam," has been changed. Price ", price); + } + + if(id==CHARTEVENT_KEYDOWN) + { + switch(lparam) + { + case KEY_B: + ///SendOrder(TRADE_ACTION_DEAL, ORDER_TYPE_BUY,Symb,last_tick.ask,price,LotSize); + ticket = OrderSend(Symb, OP_BUY, LotSize, Ask, 1, price,0); + Alert("Buy " + LotSize + " lot " + Symb + " at " + Ask + " SL at " + price); + break; + case KEY_S: + ticket = OrderSend(Symb, OP_SELL, LotSize, Bid, 1, price,0); + Alert("Sell " + LotSize + " lot " + Symb + " at " + Bid + " SL at " + price); + break; + default: + //Print("Do nothing"); + break; + } + + if(ticket<=0) + { + int error=GetLastError(); + //---- not enough money + if(error==134); + //---- 10 seconds wait + Sleep(10000); + //---- refresh price data + RefreshRates(); + } + else + { + OrderSelect(ticket,SELECT_BY_TICKET); + OrderPrint(); + } + } + } + + +//Lot Size Calculator +void LotSizeCalculate(double stopLoss) + { + double SL=0; + double PriceAsk=MarketInfo(0,MODE_ASK); + double PriceBid=MarketInfo(0,MODE_BID); + + if(stopLoss < PriceAsk) + { + SL = (PriceAsk-stopLoss)/_Point; + } + if(stopLoss > PriceAsk) + { + SL = (stopLoss-PriceBid)/_Point; + } + //Print("Stop loss distance ", SL); + +//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; + //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); + if(InpRiskBase==RISK_BASE_INPUT) + RiskBaseAmount=InpBalance; + + //Calculate the Position Size + //Print("RiskBaseAmount ", RiskBaseAmount, " MaxRiskPerTrade ", InpMaxRiskPerTrade, "Stop loss ", SL, " TickValue ", TickValue); + + LotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue)); + StoplossPips = SL; + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>InpMaxLotSize) + LotSize=InpMaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX); + //Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSize < SymbolInfoDouble(Symb,SYMBOL_VOLUME_MIN)) + { + LotSize=0; + Alert("Lot size too small"); + } + } +//+------------------------------------------------------------------+ diff --git a/LotCalTrader.ex4 b/LotCalTrader.ex4 new file mode 100644 index 0000000..13868fd Binary files /dev/null and b/LotCalTrader.ex4 differ diff --git a/LotCalTrader.mq4 b/LotCalTrader.mq4 new file mode 100644 index 0000000..3b1cbc8 --- /dev/null +++ b/LotCalTrader.mq4 @@ -0,0 +1,223 @@ +//+------------------------------------------------------------------+ +//| LotCal.mq4 | +//| Copyright 2022, Nkondog Anselme Venceslas. | +//| https://www.linkedin/in/nkondog.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, Nkondog Anselme Venceslas." +#property link "https://www.linkedin/in/nkondog.com " +#property version "1.00" +#property strict + +#define KEY_B 66 +#define KEY_S 83 + +//Parameters + +//Enumerative for the base used for risk calculation +enum ENUM_RISK_BASE + { + RISK_BASE_EQUITY=1, //EQUITY + RISK_BASE_BALANCE=2, //BALANCE + RISK_BASE_FREEMARGIN=3, //FREE MARGIN + RISK_BASE_INPUT=4, //INPUT BASE + }; + +//Enumerative for the default risk size +enum ENUM_RISK_DEFAULT_SIZE + { + RISK_DEFAULT_FIXED=1, //FIXED SIZE + RISK_DEFAULT_AUTO=2, //AUTOMATIC SIZE BASED ON RISK + }; + +input ENUM_RISK_DEFAULT_SIZE InpRiskDefaultSize=RISK_DEFAULT_AUTO; //Position Size Mode +input double InpBalance=10000.0; //Balance +input double InpDefaultLotSize=0.01; //Position Size (if fixed or if no stop loss defined) +input ENUM_RISK_BASE InpRiskBase=RISK_BASE_BALANCE; //Risk Base +input double InpMaxRiskPerTrade=0.5; //Percentage To Risk Each Trade +input double InpMinLotSize=0.01; //Minimum Position Size Allowed +input double InpMaxLotSize=100; //Maximum Position Size Allowedv + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string Symb = Symbol(); +double LotSize=InpDefaultLotSize; +double price=0.0; +double risk=0.0; +double StoplossPips=0.0; +//TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty +double TickValue=SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_VALUE); +int ticket; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + Print("The Expert Advisor with name ",MQLInfoString(MQL_PROGRAM_NAME)," is running"); +//--- enable object create events + ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true); +//--- enable object delete events + ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true); +//--- + return(INIT_SUCCEEDED); + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void OnTick() + { + displayOnChart(); + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, // Event identifier + const long& lparam, // Event parameter of long type + const double& dparam, // Event parameter of double type + const string& sparam) // Event parameter of string type + { +//--- the object has been deleted + if(id==CHARTEVENT_OBJECT_DELETE) + { + Print("The object with name ",sparam," has been deleted"); + } +//--- the object has been created + if(id==CHARTEVENT_OBJECT_CREATE) + { + Print("The object with name ",sparam," has been created"); + } + +//--- the object has been moved or its anchor point coordinates has been changed + if(id==CHARTEVENT_OBJECT_DRAG) + { + price = ObjectGetDouble(0, sparam, OBJPROP_PRICE, 0); + //Print("The anchor point coordinates of the object with name ",sparam," has been changed. Price ", price); + displayOnChart(); + } + + if(id==CHARTEVENT_KEYDOWN) + { + switch(lparam) + { + case KEY_B: + ///SendOrder(TRADE_ACTION_DEAL, ORDER_TYPE_BUY,Symb,last_tick.ask,price,LotSize); + ticket = OrderSend(Symb, OP_BUY, LotSize, Ask, 1, price,0); + Alert("Buy " + LotSize + " lot " + Symb + " at " + Ask + " SL at " + price); + break; + case KEY_S: + ticket = OrderSend(Symb, OP_SELL, LotSize, Bid, 1, price,0); + Alert("Sell " + LotSize + " lot " + Symb + " at " + Bid + " SL at " + price); + break; + default: + //Print("Do nothing"); + break; + } + + if(ticket<=0) + { + int error=GetLastError(); + //---- not enough money + if(error==134); + //---- 10 seconds wait + Sleep(10000); + //---- refresh price data + RefreshRates(); + } + else + { + OrderSelect(ticket,SELECT_BY_TICKET); + OrderPrint(); + } + } + } + + +//Lot Size Calculator +void LotSizeCalculate(double stopLoss) + { + double SL=0; + double PriceAsk=MarketInfo(0,MODE_ASK); + double PriceBid=MarketInfo(0,MODE_BID); + + if(stopLoss < PriceAsk) + { + SL = (PriceAsk-stopLoss)/_Point; + } + if(stopLoss > PriceAsk) + { + SL = (stopLoss-PriceBid)/_Point; + } + //Print("Stop loss distance ", SL); + +//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; + //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); + if(InpRiskBase==RISK_BASE_INPUT) + RiskBaseAmount=InpBalance; + + //Calculate the Position Size + //Print("RiskBaseAmount ", RiskBaseAmount, " MaxRiskPerTrade ", InpMaxRiskPerTrade, "Stop loss ", SL, " TickValue ", TickValue); + + LotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue)); + StoplossPips = SL; + } + //If the stop loss is zero then the lot size is the default one + if(SL==0) + { + LotSize=InpDefaultLotSize; + } + } +//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size + LotSize=MathFloor(LotSize/SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP); + +//Limit the lot size in case it is greater than the maximum allowed by the user + if(LotSize>InpMaxLotSize) + LotSize=InpMaxLotSize; +//Limit the lot size in case it is greater than the maximum allowed by the broker + if(LotSize>SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)) + LotSize=SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX); + //Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)); +//If the lot size is too small then set it to 0 and don't trade + if(LotSize < SymbolInfoDouble(Symb,SYMBOL_VOLUME_MIN)) + { + LotSize=0; + //Print("Lot size too small"); + } + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void displayOnChart() + { + + LotSizeCalculate(price); +//Comment("Lot size : ", LotSize); + double StopAmount = StoplossPips * LotSize * TickValue; + string text ="Lot size for "+ InpMaxRiskPerTrade +"% = " + DoubleToString(LotSize,2) + " lot (" + DoubleToString(StopAmount, 2) + " " + AccountInfoString(ACCOUNT_CURRENCY) + ")"; + string name = "Lot"; + ObjectCreate(name, OBJ_LABEL, 0, 0, 0); + ObjectSetText(name,text, 14, "Corbel Bold", YellowGreen); + ObjectSet(name, OBJPROP_CORNER, CORNER_RIGHT_UPPER); + ObjectSet(name, OBJPROP_XDISTANCE, 350); + ObjectSet(name, OBJPROP_YDISTANCE, 10); + + } +//+------------------------------------------------------------------+ diff --git a/NewCandleAlert.ex4 b/NewCandleAlert.ex4 new file mode 100644 index 0000000..4a9f365 Binary files /dev/null and b/NewCandleAlert.ex4 differ diff --git a/NewCandleAlert.mq4 b/NewCandleAlert.mq4 new file mode 100644 index 0000000..b4747a0 --- /dev/null +++ b/NewCandleAlert.mq4 @@ -0,0 +1,51 @@ +//+------------------------------------------------------------------+ +//| NewCandleAlert.mq4 | +//| Copyright 2022, Nkondog Anselme Venceslas. | +//| https://www.linkedin.com/in/nkondog | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2022, Nkondog Anselme Venceslas." +#property link "https://www.linkedin.com/in/nkondog" +#property version "1.00" +#property strict +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + newBar(); + } +//+------------------------------------------------------------------+ + +bool newBar() + { + static datetime prevTime = 0; + datetime currentTime = iTime(Symbol(), PERIOD_CURRENT, 0); + if(currentTime != prevTime) + { + prevTime = currentTime; + + Alert("New candle"); + + return(true); + } + return(false); + } \ No newline at end of file diff --git a/Symbolic link cmd.txt b/Symbolic link cmd.txt new file mode 100644 index 0000000..e3fb71e --- /dev/null +++ b/Symbolic link cmd.txt @@ -0,0 +1 @@ +New-Item -ItemType Junction -Path "C:\Users\Nkondog\AppData\Roaming\MetaQuotes\Terminal\E3E3B02889D32F38295D39BF94B6AD4A\MQL5\Include\Nkanven" -Target "D:\ITprojects\sat_bot\Include\Nkanven" \ No newline at end of file diff --git a/gemini.drawio b/gemini.drawio new file mode 100644 index 0000000..0f476fe --- /dev/null +++ b/gemini.drawio @@ -0,0 +1 @@ +1Vpbb6s4EP41kXYfWgHmlsekTXtW291Wp5V6+uiAQ7wlODKmTc6vX1PM1YSQBEjahwqPx8bMfPMxM2EEblabewrXy3+Ii/yRpribEbgdaZqtjvn/WLBNBLqtJQKPYjcRqbngGf9GQqgIaYRdFJYUGSE+w+uy0CFBgBxWkkFKyWdZbUH88l3X0EOS4NmBvix9xS5bisfSrFz+A2Fvmd5ZNcUDr2CqLJ4kXEKXfBZEYDYCN5QQllytNjfIj22X2iVZd7djNjsYRQFrs8CYPv6GLxq+ZxDTt49JdLX6uFLNZJsP6EfiicVp2TY1AXK5RcSQULYkHgmgP8ulU0qiwEXxfRQ+ynUeCFlzocqF/yHGtsK9MGKEi5Zs5YvZBfb9G+IT+nVH4BrIdnUuDxkl76gwY2tzYJp8JjllfLSd5hCikETUQU020AWuIPUQa1I0MrdxuCOyQoxu+UKKfMjwR/kkUADPy/Ry3/AL4Z5DXKVLrpo4jBum6i8OtHV8Ga38RAFMPxBlmIP6Ac6R/0RCzDAJuMqcMEZWBYWJj714gsWOK3qIRMzHAXdFGmZK5oR4Ldo0u0E2mlgARHQIelAtMf7Mgy1VWRbizFR6srJmXERAdAlvoyW8d3lqIHjXGd70+YGnc45x04uvHmAUOEuuNZtIXvlcYoae1/DLGJ/8ZVS2aD3CjyWekzA/NvZiXtUGBb0q2f6JImeJnPdQsjNdktU84keY7rF4xbYL/ucodbZdLBT+141tNaNCKLZsXLvGtnpvttUk295BP0RHsErBtlCg2EcLVgPujNdR4E7iLCjec42CRCJYx270RZnCuPXp9hcfXCnXijZOJW/x9LVu26ngdlNccLstjp4QxdymiJbeHhLH7SW0BjLcz3FmI3quxD6tKU/s9EQwP0m2ja6UQagpFXQl5xSrcoBxV8FtQW0dK4S776ONy/cRuWcO12TDHLzZE5+AZyDh+YVG/cI54erOsayUYWzsAfFZ8GoPgdcqjjKG7BmvoFyy9ATY8UVkdGctcTTzRLwNkwNqcjW6Ow/h++F1GPumUPDw+oTb0z88ObEd5Dh17pjbhm50VexU8S/nJlZNblKNxs7sDWQuP0dodAl0uyXQgVLvqcOY9FACNJRGAtyrnyYS/RKmLUehaBmEsZ82OGQSTHIQqAcHnwuRvagNPtOx0XzRUfCZ9rVVrryy91Gx8lK1a0OOwd5qr5QDCtbmJOYmHZrvVXsZ+oXVXkCua79z7TVQvpoi8ph8FeiNCOkoXzUrRb7VT7pq2LW36ZV8gdwuuNTyKktUu4HrrgT5LDAepE1QxReoEmFPOB6k7ALWEZg9OZXMwZfj7a0Et8PAN0h1Btr+ALULlsNUZ0D+AerJjxMQ/tScKnDg8StCXURrmsYXnx6aleRFr0sNh2zK68ZZAmiDWRI/liGGb4WpPHziQam9e0TUdRlDbTscYHxiDB1FwZZWrjyA3Vz4WabVpN8TZcvtl5u49xK7JC8A775viIMW5d+gP7zp4IJiXGkX4+rolLSudaOtG1YYt2WFHXXLQG9WuUU9i7ssySvVg+s/wj8b4k250HanpZRJLPtZ7HzxJjdbJl+rQtTU0jrcwMN8SGCY1Zzl7AZu8z1ZXmg6PgxDnAARUiaLCxbeVWVea6WcQ93DR+3Z5eh0vGB9o8b4qezUJoi2w/npFgk7StWjXB6qlY20fsrQ6oH35UDVjHyvvtmYY/WTM+mWBPgfs9v7v/6958KXn5Pb5Gr6+ML/vz7+/Pvu4fH1NKrxKHQxB2tKKgEJ4rTAj7/tm0Ln3fvarXb2K3WrzCxIwNKEQ03HSeqgWRVmE0vKpCaEHfBZ5WNAYMp0llFXMaLUKvRb8Bkf5t/eJmjIP2AGs/8B \ No newline at end of file