mirror of
https://github.com/rithsila/MT5-EA-Sniper-Strategy.git
synced 2026-08-15 03:38:11 +00:00
Organize project in different folders
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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; i<PositionsTotal(); i++)
|
||||
{
|
||||
//If there is a problem reading the order print the error, exit the function and return false
|
||||
if(PositionGetTicket(i) == 0)
|
||||
{
|
||||
int Error=GetLastError();
|
||||
string ErrorText=GetLastErrorText(Error);
|
||||
Print("ERROR - Unable to select the order - ",Error," - ",ErrorText);
|
||||
return false;
|
||||
}
|
||||
//If the order is not for the instrument on chart we can ignore it
|
||||
if(PositionGetSymbol(i)!=Symb)
|
||||
continue;
|
||||
//If the order has Magic Number different from the Magic Number of the EA then we can ignore it
|
||||
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber)
|
||||
continue;
|
||||
//If it is a buy order then increment the total count of buy orders
|
||||
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
|
||||
TotalOpenBuy++;
|
||||
//If it is a sell order then increment the total count of sell orders
|
||||
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
|
||||
TotalOpenSell++;
|
||||
//Increment the total orders count
|
||||
TotalOpenOrders++;
|
||||
//Find what is the open time of the most recent trade and assign it to LastBarTraded
|
||||
//this is necessary to check if we already traded in the current candle
|
||||
if((datetime)PositionGetInteger(POSITION_TIME)>LastBarTraded || 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);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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) {}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
@@ -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(gLotSize<InpMinLotSize || gLotSize < SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MIN))
|
||||
{
|
||||
gLotSize=0;
|
||||
Print("Lot size too small : ", gLotSize);
|
||||
}
|
||||
Print("LotSize3 ", gLotSize);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,132 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Parameters.mqh |
|
||||
//| Copyright 2021, Nkondog Anselme Venceslas |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
|
||||
#property link "https://www.mql5.com"
|
||||
|
||||
//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 trading time
|
||||
enum ENUM_MODE_TRADING_TIME
|
||||
{
|
||||
DAY_TRADING=0, //Day trade
|
||||
NIGHT_TRADING=1, //Night trade
|
||||
DAY_NIGHT_TRADING=2, //Both day & night trade
|
||||
ALL_DAY_TRADING=3, //Round the clock
|
||||
};
|
||||
|
||||
//Enumerative for trading time
|
||||
enum ENUM_MODE_TRADE_SIGNAL
|
||||
{
|
||||
BUY_SIGNAL=0, //Buy trade
|
||||
SELL_SIGNAL=1, //Sell trade
|
||||
NO_SIGNAL=2, //No trade
|
||||
};
|
||||
|
||||
//
|
||||
// Input Section
|
||||
//
|
||||
|
||||
input string Comment_0="=========="; //Risk Management Settings
|
||||
|
||||
input ENUM_RISK_DEFAULT_SIZE InpRiskDefaultSize=RISK_DEFAULT_AUTO; //Position Size Mode
|
||||
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 Allowed
|
||||
input int InpMaxSpread=10; //Maximum Spread Allowed
|
||||
input int InpSlippage=1; //Maximum Slippage Allowed in points
|
||||
input string Comment_01="----------------------"; //Stop loss settings
|
||||
input int InpDefaultStopLoss=200; //Default Stop Loss In Points (0=No Stop Loss)
|
||||
input int InpMinStopLoss=0; //Minimum Allowed Stop Loss In Points
|
||||
input int InpMaxStopLoss=5000; //Maximum Allowed Stop Loss In Points
|
||||
input string Comment_02="----------------------"; //Take profit settings
|
||||
input int InpDefaultTakeProfit=60; //Default Take Profit In Points (0=No Take Profit)
|
||||
input int InpMinTakeProfit=0; //Minimum Allowed Take Profit In Points
|
||||
input int InpMaxTakeProfit=5000; //Maximum Allowed Take Profit In Points
|
||||
input double InpTakeProfitPercent=1.0; //Take Profit percent on risk base
|
||||
|
||||
input string Comment_03="----------------------"; //Trading Hours Settings
|
||||
input bool InpUseTradingHours=false; //Limit Trading Hours
|
||||
input ENUM_MODE_TRADING_TIME InpTradingPeriods=ALL_DAY_TRADING; //Select trading periods
|
||||
input int InpDayTradingHourStart=7; //Day Trading Start Hour (Broker Server Hour)
|
||||
input int InpDayTradingHourEnd=21; //Day Trading End Hour (Broker Server Hour)
|
||||
input int InpNightTradingHourStart=1; //Night Trading Start Hour (Broker Server Hour)
|
||||
input int InpNightTradingHourEnd=5; //Night Trading End Hour (Broker Server Hour)
|
||||
|
||||
input string Comment_04="----------------------"; //DCA settings
|
||||
input bool InpActivateDCAHedging=false; //Active DCA Hedging
|
||||
input string InpInstrument1="EURUSD.i"; //Instrument 1
|
||||
input string InpInstrument2="USDCHF.i"; //Instrument 2
|
||||
|
||||
input string Comment_05="----------------------"; //Stop loss settings
|
||||
// Fast moving average
|
||||
input int InpPeriods = 21; // Fast periods
|
||||
input ENUM_MA_METHOD InpMethod = MODE_SMA; // Fast method
|
||||
input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; // Fast price
|
||||
input string InpComment = __FILE__; //Default trade comment
|
||||
input int InpMagicNumber = 198901; //Magic Number
|
||||
input ENUM_TIMEFRAMES InpTimeFrame = PERIOD_CURRENT;
|
||||
input int InpSameCandleCount= 2; //Same Candle in a row
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
string gSymbol = Symbol();
|
||||
double gSma;
|
||||
|
||||
int gTotalSellPositions, gTotalBuyPositions, gTotalPositions;
|
||||
bool gIsOperatingHours=false;
|
||||
bool gIsPreChecksOk=false; //Indicates if the pre checks are satisfied
|
||||
bool gIsSpreadOK=false; //Indicates if the spread is low enough to trade
|
||||
bool IsSpreadOK=false;
|
||||
bool gEmergencyClose=false; //Urgently close losing trade
|
||||
|
||||
|
||||
double gLotSize=InpDefaultLotSize;
|
||||
|
||||
int gTickValue=0;
|
||||
long Spread = SymbolInfoInteger(gSymbol,SYMBOL_SPREAD) / 100; //Check the impact. It's originally a double
|
||||
|
||||
int gOrderOpRetry = 10;
|
||||
|
||||
MqlTick last_tick, blast_tick;
|
||||
MqlDateTime dt;
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,79 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Prechecks.mqh |
|
||||
//| Copyright 2021, Nkondog Anselme Venceslas |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
|
||||
#property link "https://www.mql5.com"
|
||||
|
||||
//Perform integrity checks when the EA is loaded
|
||||
void CheckPreChecks()
|
||||
{
|
||||
gIsPreChecksOk=true;
|
||||
//Check if Live Trading is enabled
|
||||
if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
|
||||
{
|
||||
gIsPreChecksOk=false;
|
||||
Print("Live Trading is not enabled, please enable it in Metatrader and chart settings");
|
||||
return;
|
||||
}
|
||||
//Trading period verification
|
||||
if(!gIsOperatingHours)
|
||||
{
|
||||
gIsPreChecksOk=false;
|
||||
Print("Out of trading hours");
|
||||
return;
|
||||
}
|
||||
//Check if the default stop loss you are setting in above the minimum and below the maximum
|
||||
if(InpDefaultStopLoss<InpMinStopLoss || InpDefaultStopLoss>InpMaxStopLoss)
|
||||
{
|
||||
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(InpDefaultTakeProfit<InpMinTakeProfit || InpDefaultTakeProfit>InpMaxTakeProfit)
|
||||
{
|
||||
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(InpDefaultLotSize<InpMinLotSize || InpDefaultLotSize>InpMaxLotSize)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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<gTotalPositions; i++)
|
||||
{
|
||||
//If there is a problem reading the order print the error, exit the function and return false
|
||||
if(PositionGetTicket(i) == 0)
|
||||
{
|
||||
int Error=GetLastError();
|
||||
//string ErrorText=GetLastErrorText(Error);
|
||||
//Print("ERROR - Unable to select the order - ",Error," - ",ErrorText);
|
||||
Print("ERROR - Unable to select the order - ",Error," - ",Error);
|
||||
return;
|
||||
}
|
||||
//If the order is not for the instrument on chart we can ignore it
|
||||
if(PositionGetSymbol(i)!=gSymbol)
|
||||
continue;
|
||||
//If the order has Magic Number different from the Magic Number of the EA then we can ignore it
|
||||
if(PositionGetInteger(POSITION_MAGIC)!=InpMagicNumber)
|
||||
continue;
|
||||
//If it is a buy order then increment the total count of buy orders
|
||||
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
|
||||
gTotalBuyPositions++;
|
||||
//If it is a sell order then increment the total count of sell orders
|
||||
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
|
||||
gTotalSellPositions++;
|
||||
Print("POSITION_TYPE_BUY ", POSITION_TYPE_BUY, " POSITION_TYPE_SELL ", POSITION_TYPE_SELL, " PositionGetInteger(POSITION_TYPE) ", PositionGetInteger(POSITION_TYPE));
|
||||
}
|
||||
Print("Total positions ", gTotalPositions, " - Total buys ", gTotalBuyPositions, " - Total sells ", gTotalSellPositions);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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()
|
||||
{
|
||||
bool day_trading = false, night_trading = false;
|
||||
gIsOperatingHours=false;
|
||||
|
||||
//If we are not using operating hours then IsOperatingHours is true and I skip the other checks
|
||||
if(!InpUseTradingHours || InpTradingPeriods == ALL_DAY_TRADING)
|
||||
{
|
||||
gIsOperatingHours=true;
|
||||
Print("Round clock trading");
|
||||
return;
|
||||
}
|
||||
|
||||
if(InpTradingPeriods == DAY_TRADING)
|
||||
{
|
||||
Print("dt.hour ", dt.hour," >= 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
@@ -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<TradingHourEnd && In_Trade)
|
||||
{
|
||||
if(TradingHourStart == dt.hour && dt.min >= 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;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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(LotSize<MinLotSize || LotSize < SymbolInfoDouble(Symb,SYMBOL_VOLUME_MIN))
|
||||
{
|
||||
LotSize=0;
|
||||
Print("Lot size too small : ", LotSize);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DL_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 |
|
||||
//+------------------------------------------------------------------+
|
||||
#property strict
|
||||
//+------------------------------------------------------------------+
|
||||
//| defines |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//--- input parameters
|
||||
input bool rangedetection=true;
|
||||
input double upperboundary;
|
||||
input double lowerboundary;
|
||||
input int stoploss;
|
||||
input string taketype="fix";
|
||||
input int takeprofitpercent=3;
|
||||
input string timeframe="5min";
|
||||
input double rangemargin=0.0;
|
||||
|
||||
//-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
|
||||
};
|
||||
|
||||
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; //Activate 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 TradingBoundaryHour="01"; //Trading Boundary Hour
|
||||
input string TradingBoundaryMin="25"; //Trading Boundary 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 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 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 int MaxSpread=100; //Maximum Allowed Spread To Trade In Points
|
||||
input int MaxCandleIteration=100; //Max candles to check for trading range boundaries
|
||||
|
||||
//-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 = false; //Indicates if trade range has been formed
|
||||
|
||||
double TickValue=0; //Value of a tick in account currency at 1 lot
|
||||
double LotSize=0; //Lot size for the position
|
||||
double upper_boundary, lower_boundary; //Trading range boundaries
|
||||
double rangeScope;
|
||||
double Tick_Size = SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_SIZE); //Tick size
|
||||
double High[];
|
||||
double Low[];
|
||||
|
||||
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
|
||||
int Mas_Tip[6]; // Order type array
|
||||
int lotMultiplier =1; //Adust lot size according to loosing trades
|
||||
|
||||
datetime LastBarTraded;
|
||||
|
||||
MqlDateTime dt;
|
||||
MqlTick last_tick;
|
||||
|
||||
ENUM_SIGNAL_ENTRY SignalEntry=SIGNAL_ENTRY_NEUTRAL; //Entry signal variable
|
||||
ENUM_SIGNAL_EXIT SignalExit=SIGNAL_EXIT_NEUTRAL; //Exit signal variable
|
||||
@@ -0,0 +1,62 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DL_PreChecks.mqh |
|
||||
//| Copyright 2021, Nkondog Anselme Venceslas |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
|
||||
#property link "https://www.mql5.com"
|
||||
|
||||
//Perform integrity checks when the EA is loaded
|
||||
void CheckPreChecks()
|
||||
{
|
||||
IsPreChecksOk=true;
|
||||
//Check if Live Trading is enabled in MT4
|
||||
if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
|
||||
{
|
||||
IsPreChecksOk=false;
|
||||
Print("Live Trading is not enabled, please enable it in MT4 and chart settings");
|
||||
return;
|
||||
}
|
||||
//Check if the default stop loss you are setting in above the minimum and below the maximum
|
||||
if(DefaultStopLoss<MinStopLoss || DefaultStopLoss>MaxStopLoss)
|
||||
{
|
||||
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(DefaultTakeProfit<MinTakeProfit || DefaultTakeProfit>MaxTakeProfit)
|
||||
{
|
||||
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(DefaultLotSize<MinLotSize || DefaultLotSize>MaxLotSize)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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; i<PositionsTotal(); i++)
|
||||
{
|
||||
//If there is a problem reading the order print the error, exit the function and return false
|
||||
if(PositionGetTicket(i) == 0)
|
||||
{
|
||||
int Error=GetLastError();
|
||||
string ErrorText=GetLastErrorText(Error);
|
||||
Print("ERROR - Unable to select the order - ",Error," - ",ErrorText);
|
||||
return false;
|
||||
}
|
||||
//If the order is not for the instrument on chart we can ignore it
|
||||
if(PositionGetSymbol(i)!=Symb)
|
||||
continue;
|
||||
//If the order has Magic Number different from the Magic Number of the EA then we can ignore it
|
||||
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber)
|
||||
continue;
|
||||
//If it is a buy order then increment the total count of buy orders
|
||||
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
|
||||
TotalOpenBuy++;
|
||||
//If it is a sell order then increment the total count of sell orders
|
||||
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
|
||||
TotalOpenSell++;
|
||||
//Increment the total orders count
|
||||
TotalOpenOrders++;
|
||||
//Find what is the open time of the most recent trade and assign it to LastBarTraded
|
||||
//this is necessary to check if we already traded in the current candle
|
||||
if((datetime)PositionGetInteger(POSITION_TIME)>LastBarTraded || LastBarTraded==0)
|
||||
LastBarTraded=(datetime)PositionGetInteger(POSITION_TIME);
|
||||
}
|
||||
Print("Total positions ", TotalOpenOrders, " - Total buys ", TotalOpenBuy, " - Total sells ", TotalOpenSell);
|
||||
return true;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
@@ -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);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
Binary file not shown.
@@ -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; i<PositionsTotal(); i++)
|
||||
{
|
||||
//If there is a problem reading the order print the error, exit the function and return false
|
||||
if(PositionGetTicket(i) == 0)
|
||||
{
|
||||
int Error=GetLastError();
|
||||
string ErrorText=GetLastErrorText(Error);
|
||||
Print("ERROR - Unable to select the order - ",Error," - ",ErrorText);
|
||||
return false;
|
||||
}
|
||||
//If the order is not for the instrument on chart we can ignore it
|
||||
if(PositionGetSymbol(i)!=Symb)
|
||||
continue;
|
||||
//If the order has Magic Number different from the Magic Number of the EA then we can ignore it
|
||||
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber)
|
||||
continue;
|
||||
//If it is a buy order then increment the total count of buy orders
|
||||
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
|
||||
TotalOpenBuy++;
|
||||
//If it is a sell order then increment the total count of sell orders
|
||||
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
|
||||
TotalOpenSell++;
|
||||
//Increment the total orders count
|
||||
TotalOpenOrders++;
|
||||
//Find what is the open time of the most recent trade and assign it to LastBarTraded
|
||||
//this is necessary to check if we already traded in the current candle
|
||||
if((datetime)PositionGetInteger(POSITION_TIME)>LastBarTraded || LastBarTraded==0)
|
||||
LastBarTraded=(datetime)PositionGetInteger(POSITION_TIME);
|
||||
}
|
||||
Print("Total positions ", TotalOpenOrders, " - Total buys ", TotalOpenBuy, " - Total sells ", TotalOpenSell);
|
||||
return true;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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; i<index; i++) {
|
||||
|
||||
//if (result==OFX_SIGNAL_NONE) return(result);
|
||||
|
||||
signals[i].UpdateSignal();
|
||||
r2 = signals[i].GetSignal(signalType);
|
||||
|
||||
// The logic here
|
||||
// If the current result is both then just update to the r2
|
||||
// because this allows for any value
|
||||
// If r2 is both then this just leave the current result as is
|
||||
// Last test, meaning result is already none or buy or sell
|
||||
// If r2 is different then we cannot combine them
|
||||
// so the result must be none
|
||||
//
|
||||
// or like this
|
||||
//
|
||||
// result r2 gives
|
||||
// Both + Any = Any
|
||||
// Any + Both = Any
|
||||
// !Both + !Same = None
|
||||
if (result==OFX_SIGNAL_BOTH) { result = r2; }
|
||||
else if (r2==OFX_SIGNAL_BOTH) { }
|
||||
else if (result!=r2) { result = OFX_SIGNAL_NONE; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Framework.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// The only purpose of this mqh file is to provide a single
|
||||
// point to change the current framework version
|
||||
//
|
||||
// If you place an include to this file in your code you
|
||||
// will get the version framework defined in this file
|
||||
// unless your code has already included another
|
||||
// framework file
|
||||
|
||||
#ifndef _FRAMEWORK_VERSION_
|
||||
#include "Framework_2.04/Framework.mqh"
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
All.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
Auto Generated at 2021-07-10 17:11:59
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// Extension go here
|
||||
//
|
||||
#include "AllIndicators.mqh"
|
||||
#include "AllSignals.mqh"
|
||||
#include "AllTPSL.mqh"
|
||||
@@ -0,0 +1,6 @@
|
||||
//
|
||||
// Extension go here
|
||||
//
|
||||
#include "GridSignals.mqh"
|
||||
#include "GridTPSL.mqh"
|
||||
#include "GlobalEnumDefinitions.mqh"
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
All.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
Auto Generated at 2021-07-10 17:11:59
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// Extension go here
|
||||
//
|
||||
//#include "Indicators/IndicatorATR.mqh"
|
||||
#include "Indicators/IndicatorMA.mqh"
|
||||
//#include "Indicators/IndicatorTemplate.mqh"
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
All.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
Auto Generated at 2021-07-10 17:11:59
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// Extension go here
|
||||
//
|
||||
#include "Signals/SignalCombination.mqh"
|
||||
#include "Signals/SignalCrossover.mqh"
|
||||
#include "Signals/SignalTemplate.mqh"
|
||||
#include "Signals/SignalGrid.mqh"
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
All.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
Auto Generated at 2021-07-10 17:11:59
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// Extension go here
|
||||
//
|
||||
#include "TPSL/TPSLSimple.mqh"
|
||||
#include "TPSL/TPSLTemplate.mqh"
|
||||
@@ -0,0 +1,29 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| GlobalEnumDefinitions.mqh |
|
||||
//| Copyright 2021, Nkondog Anselme Venceslas |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
|
||||
#property link "https://www.mql5.com"
|
||||
|
||||
enum ENUM_TRADING_SESSION
|
||||
{
|
||||
LONDON_SESSION=1,
|
||||
NEWYORK_SESSION=2,
|
||||
TOKYO_SESSION=3,
|
||||
};
|
||||
|
||||
//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 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
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Extension go here
|
||||
//
|
||||
|
||||
#include "Signals/SignalGrid.mqh"
|
||||
@@ -0,0 +1,4 @@
|
||||
//
|
||||
// Extension go here
|
||||
//
|
||||
#include "TPSL/GridTPSL.mqh"
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
SignalCombination.mqh
|
||||
For framework version 1.0
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "../../Framework.mqh"
|
||||
|
||||
class CSignalCombination : public CSignalBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
CSignalBase *mSignals[];
|
||||
|
||||
public: // constructors
|
||||
|
||||
CSignalCombination(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CSignalBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
CSignalCombination()
|
||||
: CSignalBase()
|
||||
{ Init(); }
|
||||
~CSignalCombination() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual void AddSignal(CSignalBase *signal);
|
||||
virtual void UpdateSignal();
|
||||
|
||||
};
|
||||
|
||||
int CSignalCombination::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
ArrayResize(mSignals, 0);
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
void CSignalCombination::UpdateSignal() {
|
||||
|
||||
int index = ArraySize(mSignals);
|
||||
|
||||
if (index<=0) {
|
||||
|
||||
mEntrySignal = OFX_SIGNAL_NONE;
|
||||
mExitSignal = OFX_SIGNAL_NONE;
|
||||
|
||||
} else {
|
||||
|
||||
mSignals[0].UpdateSignal();
|
||||
mEntrySignal = mSignals[0].EntrySignal();
|
||||
mExitSignal = mSignals[0].ExitSignal();
|
||||
|
||||
for (int i = 1; i<index; i++) {
|
||||
|
||||
mSignals[i].UpdateSignal();
|
||||
if (mSignals[i].EntrySignal()!=mEntrySignal) mEntrySignal = OFX_SIGNAL_NONE;
|
||||
if (mSignals[i].ExitSignal()!=mExitSignal) mExitSignal = OFX_SIGNAL_NONE;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void CSignalCombination::AddSignal(CSignalBase *signal) {
|
||||
|
||||
int index = ArraySize(mSignals);
|
||||
ArrayResize(mSignals, index+1);
|
||||
mSignals[index] = signal;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
SignalCrossover.mqh
|
||||
For framework version 1.0
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "../../Framework.mqh"
|
||||
|
||||
class CSignalCrossover : public CSignalBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
int mIndex1;
|
||||
int mIndex2;
|
||||
|
||||
public: // constructors
|
||||
|
||||
CSignalCrossover(string symbol, ENUM_TIMEFRAMES timeframe,
|
||||
int index1=1, int index2=2)
|
||||
: CSignalBase(symbol, timeframe)
|
||||
{ Init(index1, index2); }
|
||||
CSignalCrossover(int index1=1, int index2=2)
|
||||
: CSignalBase()
|
||||
{ Init(index1, index2); }
|
||||
~CSignalCrossover() { }
|
||||
|
||||
int Init(int index1, int index2);
|
||||
|
||||
public:
|
||||
|
||||
virtual void UpdateSignal();
|
||||
|
||||
};
|
||||
|
||||
int CSignalCrossover::Init(int index1, int index2) {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
mIndex1 = index1;
|
||||
mIndex2 = index2;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
void CSignalCrossover::UpdateSignal() {
|
||||
|
||||
double fast1 = GetIndicatorData(0, mIndex1);
|
||||
double fast2 = GetIndicatorData(0, mIndex2);
|
||||
double slow1 = GetIndicatorData(1, mIndex1);
|
||||
double slow2 = GetIndicatorData(1, mIndex2);
|
||||
|
||||
// There is a less common condition where the fast
|
||||
// indicator touches the slow indicator and then
|
||||
// reverses. With the conditions below this would
|
||||
// appear like a cross.
|
||||
if ( (fast1>slow1) && !(fast2>slow2) ) { // Crossed up
|
||||
mEntrySignal = OFX_SIGNAL_BUY;
|
||||
mExitSignal = OFX_SIGNAL_SELL;
|
||||
} else
|
||||
if ( (fast1<slow1) && !(fast2<slow2) ) { // Crossed down
|
||||
mEntrySignal = OFX_SIGNAL_SELL;
|
||||
mExitSignal = OFX_SIGNAL_BUY;
|
||||
} else {
|
||||
mEntrySignal = OFX_SIGNAL_NONE;
|
||||
mExitSignal = OFX_SIGNAL_NONE;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalGrid.mqh |
|
||||
//| Copyright 2021, Nkondog Anselme Venceslas |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
|
||||
#property link "https://www.mql5.com"
|
||||
// Next line assumes this file is located in .../Frameworks/Extensions/someFolder
|
||||
#include "../../GridFramework.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalGrid : public CSignalBase
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
// Place any required member variables here
|
||||
int m_magic;
|
||||
double lastBuyOrderPrice;
|
||||
double lastSellOrderPrice;
|
||||
double openedBuyPositionPrice;
|
||||
double openedSellPositionPrice;
|
||||
|
||||
public: // constructors
|
||||
|
||||
// Add any required constructor arguments
|
||||
// e.g. CSignalXYZ(int periods, double multiplier)
|
||||
CSignalGrid()
|
||||
: CSignalBase()
|
||||
{ Init(); }
|
||||
// Same constructor with symbol and timeframe added
|
||||
CSignalGrid(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CSignalBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CSignalGrid() { }
|
||||
|
||||
// Include all arguments to match the constructor
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
// Add this line to override the same function from the parent class
|
||||
virtual void UpdateSignal();
|
||||
|
||||
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;}
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalGrid::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
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void CSignalGrid::UpdateSignal()
|
||||
{
|
||||
|
||||
// Just gather data from the indicators and
|
||||
// decide on a trade direction
|
||||
// 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, ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
SignalTemplate.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 CSignalTemplate : public CSignalBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
// Place any required member variables here
|
||||
|
||||
public: // constructors
|
||||
|
||||
// Add any required constructor arguments
|
||||
// e.g. CSignalXYZ(int periods, double multiplier)
|
||||
CSignalTemplate()
|
||||
: CSignalBase()
|
||||
{ Init(); }
|
||||
// Same constructor with symbol and timeframe added
|
||||
CSignalTemplate(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CSignalBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CSignalTemplate() { }
|
||||
|
||||
// Include all arguments to match the constructor
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
// Add this line to override the same function from the parent class
|
||||
virtual void UpdateSignal();
|
||||
|
||||
};
|
||||
|
||||
int CSignalTemplate::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
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
void CSignalTemplate::UpdateSignal() {
|
||||
|
||||
// Just gather data from the indicators and
|
||||
// decide on a trade direction
|
||||
// This is the trade decision logic
|
||||
|
||||
mExitSignal = OFX_SIGNAL_NONE; // This strategy has no exit signal
|
||||
// Just set the buy or sell signals now
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
// Next line assumes this file is located in .../Frameworks/Extensions/someFolder
|
||||
#include "../../Framework.mqh"
|
||||
|
||||
class GridTPSL : public CTPSLBase {
|
||||
|
||||
private:
|
||||
|
||||
double GetValue();
|
||||
|
||||
protected: // member variables
|
||||
|
||||
// Place any required member variables here
|
||||
|
||||
public: // constructors
|
||||
|
||||
// Add any required constructor arguments
|
||||
// e.g. CTPSLXYZ(int periods, double multiplier)
|
||||
GridTPSL() : CTPSLBase() { Init(); }
|
||||
// Same constructor with symbol and timeframe added
|
||||
GridTPSL(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CTPSLBase(symbol, timeframe) { Init(); }
|
||||
~GridTPSL() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
// Get and Set functions for additional parameters
|
||||
|
||||
// Override these from the parent class to get required values
|
||||
// GetValue here is just an example
|
||||
virtual double GetTakeProfit() { return(GetValue()); }
|
||||
virtual double GetStopLoss() { return(GetValue()); }
|
||||
|
||||
};
|
||||
|
||||
int GridTPSL::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
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
// A simple example of a value function
|
||||
double GridTPSL::GetValue() {
|
||||
|
||||
// Pulls data from an assigned indicator number 0 for bar 1 and multiplies by 2
|
||||
double value = 0;//GetIndicatorData(0, 1)*2;
|
||||
|
||||
return(value);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
TPSLSimple.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "../../Framework.mqh"
|
||||
|
||||
class CTPSLSimple : public CTPSLBase {
|
||||
|
||||
private:
|
||||
|
||||
double GetValue();
|
||||
|
||||
protected: // member variables
|
||||
|
||||
double mMultiplier;
|
||||
int mIndex;
|
||||
|
||||
public: // constructors
|
||||
|
||||
CTPSLSimple() : CTPSLBase() { Init(); }
|
||||
CTPSLSimple(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CTPSLBase(symbol, timeframe) { Init(); }
|
||||
~CTPSLSimple() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual void SetIndex(int index) { mIndex = index; }
|
||||
virtual double GetIndex() { return(mIndex); }
|
||||
|
||||
virtual void SetMultiplier(double multiplier) { mMultiplier = multiplier; }
|
||||
virtual double GetMultiplier() { return(mMultiplier); }
|
||||
|
||||
virtual double GetTakeProfit() { return(GetValue()); }
|
||||
virtual double GetStopLoss() { return(GetValue()); }
|
||||
|
||||
};
|
||||
|
||||
int CTPSLSimple::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
mMultiplier = 1.0;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
double CTPSLSimple::GetValue() {
|
||||
|
||||
double value = 0;//GetIndicatorData(0, mIndex)*mMultiplier;
|
||||
|
||||
return(value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
TPSLTemplate.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 CTPSLTemplate : public CTPSLBase {
|
||||
|
||||
private:
|
||||
|
||||
double GetValue();
|
||||
|
||||
protected: // member variables
|
||||
|
||||
// Place any required member variables here
|
||||
|
||||
public: // constructors
|
||||
|
||||
// Add any required constructor arguments
|
||||
// e.g. CTPSLXYZ(int periods, double multiplier)
|
||||
CTPSLTemplate() : CTPSLBase() { Init(); }
|
||||
// Same constructor with symbol and timeframe added
|
||||
CTPSLTemplate(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CTPSLBase(symbol, timeframe) { Init(); }
|
||||
~CTPSLTemplate() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
// Get and Set functions for additional parameters
|
||||
|
||||
// Override these from the parent class to get required values
|
||||
// GetValue here is just an example
|
||||
virtual double GetTakeProfit() { return(GetValue()); }
|
||||
virtual double GetStopLoss() { return(GetValue()); }
|
||||
|
||||
};
|
||||
|
||||
int CTPSLTemplate::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
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
// A simple example of a value function
|
||||
double CTPSLTemplate::GetValue() {
|
||||
|
||||
// Pulls data from an assigned indicator number 0 for bar 1 and multiplies by 2
|
||||
double value = 0;//GetIndicatorData(0, 1)*2;
|
||||
|
||||
return(value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Framework.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// The only purpose of this mqh file is to provide a single
|
||||
// point to change the current framework version
|
||||
//
|
||||
// If you place an include to this file in your code you
|
||||
// will get the version framework defined in this file
|
||||
// unless your code has already included another
|
||||
// framework file
|
||||
|
||||
#ifndef _FRAMEWORK_VERSION_
|
||||
#include "Framework_2.04/Framework.mqh"
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
CommonBase.mqh
|
||||
For framework version 1.0
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
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;
|
||||
return(initResult); }
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
ExpertBase.mqh
|
||||
For framework version 1.0
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
#include "Signals/SignalBase.mqh"
|
||||
#include "Trade/Trade.mqh"
|
||||
|
||||
class CExpertBase : public CCommonBase {
|
||||
|
||||
protected:
|
||||
|
||||
int mMagicNumber;
|
||||
string mTradeComment;
|
||||
|
||||
double mVolume;
|
||||
|
||||
datetime mLastBarTime;
|
||||
datetime mBarTime;
|
||||
|
||||
CSignalBase *mEntrySignal;
|
||||
CSignalBase *mExitSignal;
|
||||
|
||||
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 SetTradeComment(string comment) { mTradeComment = comment; }
|
||||
virtual void SetMagic(int magicNumber) { mMagicNumber = magicNumber;
|
||||
Trade.SetExpertMagicNumber(magicNumber); }
|
||||
|
||||
public: // Setup
|
||||
|
||||
virtual void AddEntrySignal(CSignalBase *signal) { mEntrySignal=signal; }
|
||||
virtual void AddExitSignal(CSignalBase *signal) { mExitSignal=signal; }
|
||||
|
||||
public: // Event handlers
|
||||
|
||||
virtual int OnInit() { return(InitResult()); }
|
||||
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 void OnTesterInit() { return; }
|
||||
virtual void OnTesterPass() { return; }
|
||||
virtual void OnTesterDeinit() { return; }
|
||||
virtual void OnBookEvent() { return; }
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
CExpertBase::~CExpertBase() {
|
||||
|
||||
}
|
||||
|
||||
int CExpertBase::Init(int magicNumber, string tradeComment) {
|
||||
|
||||
if (mInitResult!=INIT_SUCCEEDED) return(mInitResult);
|
||||
|
||||
mTradeComment = tradeComment;
|
||||
SetMagic(magicNumber);
|
||||
|
||||
mLastBarTime = 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
|
||||
//
|
||||
if (mEntrySignal!=NULL) mEntrySignal.UpdateSignal();
|
||||
if (mEntrySignal!=mExitSignal) {
|
||||
if (mExitSignal!=NULL) mExitSignal.UpdateSignal();
|
||||
}
|
||||
|
||||
//
|
||||
// Should any trades be closed
|
||||
//
|
||||
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
|
||||
//
|
||||
if (mEntrySignal!=NULL) {
|
||||
if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BOTH) {
|
||||
Trade.Buy(mVolume, mSymbol);
|
||||
Trade.Sell(mVolume, mSymbol);
|
||||
} else
|
||||
if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BUY) {
|
||||
Trade.Buy(mVolume, mSymbol);
|
||||
} else
|
||||
if (mEntrySignal.EntrySignal()==OFX_SIGNAL_SELL) {
|
||||
Trade.Sell(mVolume, mSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
return(true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Framework_1.00.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _FRAMEWORK_VERSION_
|
||||
|
||||
#define _FRAMEWORK_VERSION_ "1.00"
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
#include "Indicators/AllIndicators.mqh"
|
||||
#include "Signals/AllSignals.mqh"
|
||||
#include "ExpertBase.mqh"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
AllSignals.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include "SignalBase.mqh"
|
||||
|
||||
//
|
||||
// Other signals go here
|
||||
//
|
||||
#include "Crossover/SignalCrossover.mqh"
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
SignalCrossover.mqh
|
||||
For framework version 1.0
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "../SignalBase.mqh"
|
||||
|
||||
class CSignalCrossover : public CSignalBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
int mIndex1;
|
||||
int mIndex2;
|
||||
|
||||
public: // constructors
|
||||
|
||||
CSignalCrossover(string symbol, ENUM_TIMEFRAMES timeframe,
|
||||
int index1=1, int index2=2)
|
||||
: CSignalBase(symbol, timeframe)
|
||||
{ Init(index1, index2); }
|
||||
CSignalCrossover(int index1=1, int index2=2)
|
||||
: CSignalBase()
|
||||
{ Init(index1, index2); }
|
||||
~CSignalCrossover() { }
|
||||
|
||||
int Init(int index1, int index2);
|
||||
|
||||
public:
|
||||
|
||||
virtual void UpdateSignal();
|
||||
|
||||
};
|
||||
|
||||
int CSignalCrossover::Init(int index1, int index2) {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
mIndex1 = index1;
|
||||
mIndex2 = index2;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
void CSignalCrossover::UpdateSignal() {
|
||||
|
||||
double fast1 = GetIndicatorData(0, mIndex1);
|
||||
double fast2 = GetIndicatorData(0, mIndex2);
|
||||
double slow1 = GetIndicatorData(1, mIndex1);
|
||||
double slow2 = GetIndicatorData(1, mIndex2);
|
||||
|
||||
// There is a less common condition where the fast
|
||||
// indicator touches the slow indicator and then
|
||||
// reverses. With the conditions below this would
|
||||
// appear like a cross.
|
||||
if ( (fast1>slow1) && !(fast2>slow2) ) { // Crossed up
|
||||
mEntrySignal = OFX_SIGNAL_BUY;
|
||||
mExitSignal = OFX_SIGNAL_SELL;
|
||||
} else
|
||||
if ( (fast1<slow1) && !(fast2<slow2) ) { // Crossed down
|
||||
mEntrySignal = OFX_SIGNAL_SELL;
|
||||
mExitSignal = OFX_SIGNAL_BUY;
|
||||
} else {
|
||||
mEntrySignal = OFX_SIGNAL_NONE;
|
||||
mExitSignal = OFX_SIGNAL_NONE;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
SignalBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "../CommonBase.mqh"
|
||||
#include "../Indicators/IndicatorBase.mqh"
|
||||
|
||||
struct SIndicatorItem {
|
||||
CIndicatorBase *indicator;
|
||||
int bufferNum;
|
||||
};
|
||||
|
||||
enum ENUM_OFX_SIGNAL_DIRECTION {
|
||||
OFX_SIGNAL_NONE = 0,
|
||||
OFX_SIGNAL_BUY = 1,
|
||||
OFX_SIGNAL_SELL = 2,
|
||||
OFX_SIGNAL_BOTH = 3
|
||||
};
|
||||
|
||||
class CSignalBase : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
ENUM_OFX_SIGNAL_DIRECTION mEntrySignal;
|
||||
ENUM_OFX_SIGNAL_DIRECTION mExitSignal;
|
||||
SIndicatorItem mIndicatorList[];
|
||||
|
||||
public: // constructors
|
||||
|
||||
CSignalBase() : CCommonBase()
|
||||
{ Init(); }
|
||||
CSignalBase(string symbol, ENUM_TIMEFRAMES timeframe) : CCommonBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CSignalBase() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual void UpdateSignal() { return; }
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION EntrySignal() { return(mEntrySignal); }
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION ExitSignal() { return(mExitSignal); }
|
||||
|
||||
virtual void AddIndicator(CIndicatorBase *indicator, int bufferNum);
|
||||
virtual double GetIndicatorData(int indicatorNum, int index);
|
||||
|
||||
};
|
||||
|
||||
int CSignalBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
mEntrySignal = OFX_SIGNAL_NONE;
|
||||
mExitSignal = OFX_SIGNAL_NONE;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
void CSignalBase::AddIndicator(CIndicatorBase *indicator, int bufferNum) {
|
||||
|
||||
SIndicatorItem indicatorItem = {NULL, 0};
|
||||
indicatorItem.indicator = indicator;
|
||||
indicatorItem.bufferNum = bufferNum;
|
||||
int cnt = ArraySize(mIndicatorList);
|
||||
ArrayResize(mIndicatorList, cnt+1);
|
||||
mIndicatorList[cnt] = indicatorItem;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
double CSignalBase::GetIndicatorData(int indicatorNum,int index) {
|
||||
|
||||
return(mIndicatorList[indicatorNum].indicator.GetData(mIndicatorList[indicatorNum].bufferNum, index));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __MQL4__
|
||||
#include "Trade_mql4.mqh"
|
||||
#endif
|
||||
#ifdef __MQL5__
|
||||
#include "Trade_mql5.mqh"
|
||||
#endif
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
(For MQL4)
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "../CommonBase.mqh"
|
||||
|
||||
enum ENUM_POSITION_TYPE {
|
||||
POSITION_TYPE_BUY = ORDER_TYPE_BUY,
|
||||
POSITION_TYPE_SELL = ORDER_TYPE_SELL
|
||||
};
|
||||
|
||||
class CTradeCustom : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
int mMagic; // expert magic number
|
||||
|
||||
public: // constructors
|
||||
|
||||
CTradeCustom();
|
||||
~CTradeCustom();
|
||||
|
||||
public:
|
||||
|
||||
ulong RequestMagic() { return(mMagic); }
|
||||
void SetExpertMagicNumber(const int magic) { mMagic=magic; }
|
||||
|
||||
double BuyPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_ASK)); }
|
||||
double SellPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_BID)); }
|
||||
|
||||
bool Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
|
||||
bool 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="");
|
||||
|
||||
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const int deviation=ULONG_MAX);
|
||||
|
||||
};
|
||||
|
||||
CTradeCustom::CTradeCustom() {
|
||||
|
||||
mMagic = 0;
|
||||
|
||||
}
|
||||
|
||||
CTradeCustom::~CTradeCustom() {
|
||||
|
||||
}
|
||||
|
||||
bool CTradeCustom::Buy(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 = BuyPrice(symbol);
|
||||
int ticket = OrderSend(symbol, ORDER_TYPE_BUY, volume, price, 0, sl, tp, comment, mMagic);
|
||||
return(ticket>0);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
(For MQL5)
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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; i<index; i++) {
|
||||
|
||||
//if (result==OFX_SIGNAL_NONE) return(result);
|
||||
|
||||
signals[i].UpdateSignal();
|
||||
r2 = signals[i].GetSignal(signalType);
|
||||
|
||||
// The logic here
|
||||
// If the current result is both then just update to the r2
|
||||
// because this allows for any value
|
||||
// If r2 is both then this just leave the current result as is
|
||||
// Last test, meaning result is already none or buy or sell
|
||||
// If r2 is different then we cannot combine them
|
||||
// so the result must be none
|
||||
//
|
||||
// or like this
|
||||
//
|
||||
// result r2 gives
|
||||
// Both + Any = Any
|
||||
// Any + Both = Any
|
||||
// !Both + !Same = None
|
||||
if (result==OFX_SIGNAL_BOTH) { result = r2; }
|
||||
else if (r2==OFX_SIGNAL_BOTH) { }
|
||||
else if (result!=r2) { result = OFX_SIGNAL_NONE; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Framework_2.03.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// History
|
||||
// 1.00 - First version, not well version controlled
|
||||
// 2.00 - Changed framework structure, functionally same as 1.00
|
||||
// 2.01 - Added TP and SL
|
||||
// 2.02 - Move compound signals into expertbase
|
||||
// Templates now use common files between mq4 and mq5
|
||||
// MakeMQH batch script also recreates framework.mqh
|
||||
// 2.03 - Added macros to CommonBase to standardise init checking
|
||||
// Moved base classes up one level and removed unnecessary folders
|
||||
|
||||
#ifndef _FRAMEWORK_VERSION_
|
||||
|
||||
#define _FRAMEWORK_VERSION_ "2.03"
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
|
||||
#include "Trade/Trade.mqh"
|
||||
|
||||
#include "IndicatorBase.mqh"
|
||||
#include "SignalBase.mqh"
|
||||
#include "TPSLBase.mqh"
|
||||
|
||||
#include "ExpertBase.mqh"
|
||||
|
||||
#include "../Extensions/AllExtensions.mqh"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
IndicatorBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
|
||||
class CIndicatorBase : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
// Only used for MQL5
|
||||
int mIndicatorHandle;
|
||||
|
||||
public: // constructors
|
||||
|
||||
CIndicatorBase() : CCommonBase()
|
||||
{ Init(); }
|
||||
CIndicatorBase(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CCommonBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CIndicatorBase();
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual double GetData(const int index) { return(GetData(0,index)); }
|
||||
virtual double GetData(const int bufferNum, const int index){ return (0); }
|
||||
|
||||
};
|
||||
|
||||
CIndicatorBase::~CIndicatorBase() {
|
||||
|
||||
#ifdef __MQL5__
|
||||
|
||||
if (mIndicatorHandle!=INVALID_HANDLE) IndicatorRelease(mIndicatorHandle);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int CIndicatorBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
mIndicatorHandle = INVALID_HANDLE;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
SignalBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
#include "IndicatorBase.mqh"
|
||||
|
||||
//// New
|
||||
//// This is to maintain compatibility and allow sub classes to still
|
||||
//// use mEntrySignal= or mExitSignal=
|
||||
//// mEntrySignal and mExitSignal are effectively deprecated now
|
||||
#define mEntrySignal mSignalValues[OFX_ENTRY_SIGNAL] // Deprecated
|
||||
#define mExitSignal mSignalValues[OFX_EXIT_SIGNAL] // Deprecated
|
||||
|
||||
struct SIndicatorItem {
|
||||
CIndicatorBase *indicator;
|
||||
int bufferNum;
|
||||
};
|
||||
|
||||
//// New
|
||||
enum ENUM_OFX_SIGNAL_TYPE {
|
||||
OFX_ENTRY_SIGNAL,
|
||||
OFX_EXIT_SIGNAL
|
||||
};
|
||||
|
||||
enum ENUM_OFX_SIGNAL_DIRECTION {
|
||||
OFX_SIGNAL_NONE = 0,
|
||||
OFX_SIGNAL_BUY = 1,
|
||||
OFX_SIGNAL_SELL = 2,
|
||||
OFX_SIGNAL_BOTH = 3
|
||||
};
|
||||
|
||||
class CSignalBase : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
//// Replaced
|
||||
ENUM_OFX_SIGNAL_DIRECTION mSignalValues[2];
|
||||
////ENUM_OFX_SIGNAL_DIRECTION mEntrySignal;
|
||||
////ENUM_OFX_SIGNAL_DIRECTION mExitSignal;
|
||||
SIndicatorItem mIndicatorList[];
|
||||
|
||||
public: // constructors
|
||||
|
||||
CSignalBase() : CCommonBase()
|
||||
{ Init(); }
|
||||
CSignalBase(string symbol, ENUM_TIMEFRAMES timeframe) : CCommonBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CSignalBase() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual void UpdateSignal() { return; }
|
||||
//// Changed - maintain backward compatibility
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION EntrySignal() { return(mSignalValues[OFX_ENTRY_SIGNAL]); }
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION ExitSignal() { return(mSignalValues[OFX_EXIT_SIGNAL]); }
|
||||
//// New, and shows my lack of planning
|
||||
virtual void SetSignal(ENUM_OFX_SIGNAL_TYPE type,
|
||||
ENUM_OFX_SIGNAL_DIRECTION value)
|
||||
{ mSignalValues[type] = value; }
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION GetSignal(ENUM_OFX_SIGNAL_TYPE type)
|
||||
{ return(mSignalValues[type]); }
|
||||
|
||||
virtual void AddIndicator(CIndicatorBase *indicator, int bufferNum);
|
||||
virtual double GetIndicatorData(int indicatorNum, int index);
|
||||
|
||||
};
|
||||
|
||||
int CSignalBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
//// Replaced
|
||||
ArrayInitialize(mSignalValues, OFX_SIGNAL_NONE);
|
||||
////mEntrySignal = OFX_SIGNAL_NONE;
|
||||
////mExitSignal = OFX_SIGNAL_NONE;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
void CSignalBase::AddIndicator(CIndicatorBase *indicator, int bufferNum) {
|
||||
|
||||
SIndicatorItem indicatorItem = {NULL, 0};
|
||||
indicatorItem.indicator = indicator;
|
||||
indicatorItem.bufferNum = bufferNum;
|
||||
int cnt = ArraySize(mIndicatorList);
|
||||
ArrayResize(mIndicatorList, cnt+1);
|
||||
mIndicatorList[cnt] = indicatorItem;
|
||||
if (indicator.InitResult()!=INIT_SUCCEEDED) {
|
||||
InitError("",indicator.InitResult());
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
double CSignalBase::GetIndicatorData(int indicatorNum,int index) {
|
||||
|
||||
return(mIndicatorList[indicatorNum].indicator.GetData(mIndicatorList[indicatorNum].bufferNum, index));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
TPSLBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "Signalbase.mqh"
|
||||
|
||||
class CTPSLBase : public CSignalBase {
|
||||
|
||||
private:
|
||||
|
||||
public: // constructors
|
||||
|
||||
CTPSLBase() : CSignalBase() { Init(); }
|
||||
CTPSLBase(string symbol, ENUM_TIMEFRAMES timeframe) : CSignalBase(symbol, timeframe) { Init(); }
|
||||
~CTPSLBase() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual double GetTakeProfit() { return(0.0); }
|
||||
virtual double GetStopLoss() { return(0.0); }
|
||||
|
||||
};
|
||||
|
||||
int CTPSLBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __MQL4__
|
||||
#include "Trade_mql4.mqh"
|
||||
#endif
|
||||
#ifdef __MQL5__
|
||||
#include "Trade_mql5.mqh"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
(For MQL4)
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "..\CommonBase.mqh"
|
||||
|
||||
struct MqlTradeRequest {
|
||||
int action; // Trade operation type (as int here)
|
||||
ulong magic; // Expert Advisor ID (magic number)
|
||||
ulong order; // Order ticket
|
||||
string symbol; // Trade symbol
|
||||
double volume; // Requested volume for a deal in lots
|
||||
double price; // Price
|
||||
double stoplimit; // StopLimit level of the order
|
||||
double sl; // Stop Loss level of the order
|
||||
double tp; // Take Profit level of the order
|
||||
ulong deviation; // Maximal possible deviation from the requested price
|
||||
ENUM_ORDER_TYPE type; // Order type
|
||||
int type_filling; // Order execution type (int here)
|
||||
int type_time; // Order expiration type (int here)
|
||||
datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type)
|
||||
string comment; // Order comment
|
||||
ulong position; // Position ticket
|
||||
ulong position_by; // The ticket of an opposite position
|
||||
};
|
||||
|
||||
enum ENUM_POSITION_TYPE {
|
||||
POSITION_TYPE_BUY = ORDER_TYPE_BUY,
|
||||
POSITION_TYPE_SELL = ORDER_TYPE_SELL
|
||||
};
|
||||
|
||||
class CTradeCustom : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
int mMagic; // expert magic number
|
||||
|
||||
public: // constructors
|
||||
|
||||
CTradeCustom();
|
||||
~CTradeCustom();
|
||||
|
||||
public:
|
||||
|
||||
ulong RequestMagic() { return(mMagic); }
|
||||
void SetExpertMagicNumber(const int magic) { mMagic=magic; }
|
||||
|
||||
double BuyPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_ASK)); }
|
||||
double SellPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_BID)); }
|
||||
|
||||
bool Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
|
||||
bool 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="");
|
||||
|
||||
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const int deviation=ULONG_MAX);
|
||||
////New
|
||||
void PositionCountByType(const string symbol, int &count[]);
|
||||
|
||||
};
|
||||
|
||||
CTradeCustom::CTradeCustom() {
|
||||
|
||||
mMagic = 0;
|
||||
|
||||
}
|
||||
|
||||
CTradeCustom::~CTradeCustom() {
|
||||
|
||||
}
|
||||
|
||||
bool CTradeCustom::Buy(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 = BuyPrice(symbol);
|
||||
int ticket = OrderSend(symbol, ORDER_TYPE_BUY, volume, price, 0, sl, tp, comment, mMagic);
|
||||
return(ticket>0);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
(For MQL5)
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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; i<index; i++) {
|
||||
|
||||
//if (result==OFX_SIGNAL_NONE) return(result);
|
||||
|
||||
signals[i].UpdateSignal();
|
||||
r2 = signals[i].GetSignal(signalType);
|
||||
|
||||
// The logic here
|
||||
// If the current result is both then just update to the r2
|
||||
// because this allows for any value
|
||||
// If r2 is both then this just leave the current result as is
|
||||
// Last test, meaning result is already none or buy or sell
|
||||
// If r2 is different then we cannot combine them
|
||||
// so the result must be none
|
||||
//
|
||||
// or like this
|
||||
//
|
||||
// result r2 gives
|
||||
// Both + Any = Any
|
||||
// Any + Both = Any
|
||||
// !Both + !Same = None
|
||||
if (result==OFX_SIGNAL_BOTH) { result = r2; }
|
||||
else if (r2==OFX_SIGNAL_BOTH) { }
|
||||
else if (result!=r2) { result = OFX_SIGNAL_NONE; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Framework_2.03.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// History
|
||||
// 1.00 - First version, not well version controlled
|
||||
// 2.00 - Changed framework structure, functionally same as 1.00
|
||||
// 2.01 - Added TP and SL
|
||||
// 2.02 - Move compound signals into expertbase
|
||||
// Templates now use common files between mq4 and mq5
|
||||
// MakeMQH batch script also recreates framework.mqh
|
||||
// 2.03 - Added macros to CommonBase to standardise init checking
|
||||
// Moved base classes up one level and removed unnecessary folders
|
||||
|
||||
#ifndef _FRAMEWORK_VERSION_
|
||||
|
||||
#define _FRAMEWORK_VERSION_ "2.03"
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
|
||||
#include "Trade/Trade.mqh"
|
||||
|
||||
#include "IndicatorBase.mqh"
|
||||
#include "SignalBase.mqh"
|
||||
#include "TPSLBase.mqh"
|
||||
|
||||
#include "ExpertBase.mqh"
|
||||
|
||||
#include "../Extensions/AllExtensions.mqh"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
IndicatorBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
|
||||
class CIndicatorBase : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
// Only used for MQL5
|
||||
int mIndicatorHandle;
|
||||
|
||||
public: // constructors
|
||||
|
||||
CIndicatorBase() : CCommonBase()
|
||||
{ Init(); }
|
||||
CIndicatorBase(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CCommonBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CIndicatorBase();
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual double GetData(const int index) { return(GetData(0,index)); }
|
||||
virtual double GetData(const int bufferNum, const int index){ return (0); }
|
||||
|
||||
};
|
||||
|
||||
CIndicatorBase::~CIndicatorBase() {
|
||||
|
||||
#ifdef __MQL5__
|
||||
|
||||
if (mIndicatorHandle!=INVALID_HANDLE) IndicatorRelease(mIndicatorHandle);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int CIndicatorBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
mIndicatorHandle = INVALID_HANDLE;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
SignalBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
#include "IndicatorBase.mqh"
|
||||
|
||||
//// New
|
||||
//// This is to maintain compatibility and allow sub classes to still
|
||||
//// use mEntrySignal= or mExitSignal=
|
||||
//// mEntrySignal and mExitSignal are effectively deprecated now
|
||||
#define mEntrySignal mSignalValues[OFX_ENTRY_SIGNAL] // Deprecated
|
||||
#define mExitSignal mSignalValues[OFX_EXIT_SIGNAL] // Deprecated
|
||||
|
||||
struct SIndicatorItem {
|
||||
CIndicatorBase *indicator;
|
||||
int bufferNum;
|
||||
};
|
||||
|
||||
//// New
|
||||
enum ENUM_OFX_SIGNAL_TYPE {
|
||||
OFX_ENTRY_SIGNAL,
|
||||
OFX_EXIT_SIGNAL
|
||||
};
|
||||
|
||||
enum ENUM_OFX_SIGNAL_DIRECTION {
|
||||
OFX_SIGNAL_NONE = 0,
|
||||
OFX_SIGNAL_BUY = 1,
|
||||
OFX_SIGNAL_SELL = 2,
|
||||
OFX_SIGNAL_BOTH = 3
|
||||
};
|
||||
|
||||
class CSignalBase : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
//// Replaced
|
||||
ENUM_OFX_SIGNAL_DIRECTION mSignalValues[2];
|
||||
////ENUM_OFX_SIGNAL_DIRECTION mEntrySignal;
|
||||
////ENUM_OFX_SIGNAL_DIRECTION mExitSignal;
|
||||
SIndicatorItem mIndicatorList[];
|
||||
|
||||
public: // constructors
|
||||
|
||||
CSignalBase() : CCommonBase()
|
||||
{ Init(); }
|
||||
CSignalBase(string symbol, ENUM_TIMEFRAMES timeframe) : CCommonBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CSignalBase() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual void UpdateSignal() { return; }
|
||||
//// Changed - maintain backward compatibility
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION EntrySignal() { return(mSignalValues[OFX_ENTRY_SIGNAL]); }
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION ExitSignal() { return(mSignalValues[OFX_EXIT_SIGNAL]); }
|
||||
//// New, and shows my lack of planning
|
||||
virtual void SetSignal(ENUM_OFX_SIGNAL_TYPE type,
|
||||
ENUM_OFX_SIGNAL_DIRECTION value)
|
||||
{ mSignalValues[type] = value; }
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION GetSignal(ENUM_OFX_SIGNAL_TYPE type)
|
||||
{ return(mSignalValues[type]); }
|
||||
|
||||
virtual void AddIndicator(CIndicatorBase *indicator, int bufferNum);
|
||||
virtual double GetIndicatorData(int indicatorNum, int index);
|
||||
|
||||
};
|
||||
|
||||
int CSignalBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
//// Replaced
|
||||
ArrayInitialize(mSignalValues, OFX_SIGNAL_NONE);
|
||||
////mEntrySignal = OFX_SIGNAL_NONE;
|
||||
////mExitSignal = OFX_SIGNAL_NONE;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
void CSignalBase::AddIndicator(CIndicatorBase *indicator, int bufferNum) {
|
||||
|
||||
SIndicatorItem indicatorItem = {NULL, 0};
|
||||
indicatorItem.indicator = indicator;
|
||||
indicatorItem.bufferNum = bufferNum;
|
||||
int cnt = ArraySize(mIndicatorList);
|
||||
ArrayResize(mIndicatorList, cnt+1);
|
||||
mIndicatorList[cnt] = indicatorItem;
|
||||
if (indicator.InitResult()!=INIT_SUCCEEDED) {
|
||||
InitError("",indicator.InitResult());
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
double CSignalBase::GetIndicatorData(int indicatorNum,int index) {
|
||||
|
||||
return(mIndicatorList[indicatorNum].indicator.GetData(mIndicatorList[indicatorNum].bufferNum, index));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
TPSLBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "Signalbase.mqh"
|
||||
|
||||
class CTPSLBase : public CSignalBase {
|
||||
|
||||
private:
|
||||
|
||||
public: // constructors
|
||||
|
||||
CTPSLBase() : CSignalBase() { Init(); }
|
||||
CTPSLBase(string symbol, ENUM_TIMEFRAMES timeframe) : CSignalBase(symbol, timeframe) { Init(); }
|
||||
~CTPSLBase() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual double GetTakeProfit() { return(0.0); }
|
||||
virtual double GetStopLoss() { return(0.0); }
|
||||
|
||||
};
|
||||
|
||||
int CTPSLBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __MQL4__
|
||||
#include "Trade_mql4.mqh"
|
||||
#endif
|
||||
#ifdef __MQL5__
|
||||
#include "Trade_mql5.mqh"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
(For MQL4)
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "..\CommonBase.mqh"
|
||||
|
||||
struct MqlTradeRequest {
|
||||
int action; // Trade operation type (as int here)
|
||||
ulong magic; // Expert Advisor ID (magic number)
|
||||
ulong order; // Order ticket
|
||||
string symbol; // Trade symbol
|
||||
double volume; // Requested volume for a deal in lots
|
||||
double price; // Price
|
||||
double stoplimit; // StopLimit level of the order
|
||||
double sl; // Stop Loss level of the order
|
||||
double tp; // Take Profit level of the order
|
||||
ulong deviation; // Maximal possible deviation from the requested price
|
||||
ENUM_ORDER_TYPE type; // Order type
|
||||
int type_filling; // Order execution type (int here)
|
||||
int type_time; // Order expiration type (int here)
|
||||
datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type)
|
||||
string comment; // Order comment
|
||||
ulong position; // Position ticket
|
||||
ulong position_by; // The ticket of an opposite position
|
||||
};
|
||||
|
||||
enum ENUM_POSITION_TYPE {
|
||||
POSITION_TYPE_BUY = ORDER_TYPE_BUY,
|
||||
POSITION_TYPE_SELL = ORDER_TYPE_SELL
|
||||
};
|
||||
|
||||
class CTradeCustom : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
int mMagic; // expert magic number
|
||||
|
||||
public: // constructors
|
||||
|
||||
CTradeCustom();
|
||||
~CTradeCustom();
|
||||
|
||||
public:
|
||||
|
||||
ulong RequestMagic() { return(mMagic); }
|
||||
void SetExpertMagicNumber(const int magic) { mMagic=magic; }
|
||||
|
||||
double BuyPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_ASK)); }
|
||||
double SellPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_BID)); }
|
||||
|
||||
bool Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
|
||||
bool 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="");
|
||||
|
||||
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const int deviation=ULONG_MAX);
|
||||
////New
|
||||
void PositionCountByType(const string symbol, int &count[]);
|
||||
|
||||
};
|
||||
|
||||
CTradeCustom::CTradeCustom() {
|
||||
|
||||
mMagic = 0;
|
||||
|
||||
}
|
||||
|
||||
CTradeCustom::~CTradeCustom() {
|
||||
|
||||
}
|
||||
|
||||
bool CTradeCustom::Buy(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 = BuyPrice(symbol);
|
||||
int ticket = OrderSend(symbol, ORDER_TYPE_BUY, volume, price, 0, sl, tp, comment, mMagic);
|
||||
return(ticket>0);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
(For MQL5)
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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; i<index; i++) {
|
||||
|
||||
//if (result==OFX_SIGNAL_NONE) return(result);
|
||||
|
||||
signals[i].UpdateSignal();
|
||||
r2 = signals[i].GetSignal(signalType);
|
||||
|
||||
// The logic here
|
||||
// If the current result is both then just update to the r2
|
||||
// because this allows for any value
|
||||
// If r2 is both then this just leave the current result as is
|
||||
// Last test, meaning result is already none or buy or sell
|
||||
// If r2 is different then we cannot combine them
|
||||
// so the result must be none
|
||||
//
|
||||
// or like this
|
||||
//
|
||||
// result r2 gives
|
||||
// Both + Any = Any
|
||||
// Any + Both = Any
|
||||
// !Both + !Same = None
|
||||
if (result==OFX_SIGNAL_BOTH) { result = r2; }
|
||||
else if (r2==OFX_SIGNAL_BOTH) { }
|
||||
else if (result!=r2) { result = OFX_SIGNAL_NONE; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Framework_2.03.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// History
|
||||
// 1.00 - First version, not well version controlled
|
||||
// 2.00 - Changed framework structure, functionally same as 1.00
|
||||
// 2.01 - Added TP and SL
|
||||
// 2.02 - Move compound signals into expertbase
|
||||
// Templates now use common files between mq4 and mq5
|
||||
// MakeMQH batch script also recreates framework.mqh
|
||||
// 2.03 - Added macros to CommonBase to standardise init checking
|
||||
// Moved base classes up one level and removed unnecessary folders
|
||||
|
||||
#ifndef _FRAMEWORK_VERSION_
|
||||
|
||||
#define _FRAMEWORK_VERSION_ "1.0"
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
|
||||
#include "Trade/Trade.mqh"
|
||||
|
||||
#include "IndicatorBase.mqh"
|
||||
#include "SignalBase.mqh"
|
||||
#include "TPSLBase.mqh"
|
||||
|
||||
#include "ExpertBase.mqh"
|
||||
|
||||
#include "../Extensions/AllExtensions.mqh"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
IndicatorBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
|
||||
class CIndicatorBase : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
// Only used for MQL5
|
||||
int mIndicatorHandle;
|
||||
|
||||
public: // constructors
|
||||
|
||||
CIndicatorBase() : CCommonBase()
|
||||
{ Init(); }
|
||||
CIndicatorBase(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CCommonBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CIndicatorBase();
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual double GetData(const int index) { return(GetData(0,index)); }
|
||||
virtual double GetData(const int bufferNum, const int index){ return (0); }
|
||||
|
||||
};
|
||||
|
||||
CIndicatorBase::~CIndicatorBase() {
|
||||
|
||||
#ifdef __MQL5__
|
||||
|
||||
if (mIndicatorHandle!=INVALID_HANDLE) IndicatorRelease(mIndicatorHandle);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int CIndicatorBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
mIndicatorHandle = INVALID_HANDLE;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
SignalBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
#include "IndicatorBase.mqh"
|
||||
|
||||
//// New
|
||||
//// This is to maintain compatibility and allow sub classes to still
|
||||
//// use mEntrySignal= or mExitSignal=
|
||||
//// mEntrySignal and mExitSignal are effectively deprecated now
|
||||
#define mEntrySignal mSignalValues[OFX_ENTRY_SIGNAL] // Deprecated
|
||||
#define mExitSignal mSignalValues[OFX_EXIT_SIGNAL] // Deprecated
|
||||
|
||||
struct SIndicatorItem {
|
||||
CIndicatorBase *indicator;
|
||||
int bufferNum;
|
||||
};
|
||||
|
||||
//// New
|
||||
enum ENUM_OFX_SIGNAL_TYPE {
|
||||
OFX_ENTRY_SIGNAL,
|
||||
OFX_EXIT_SIGNAL
|
||||
};
|
||||
|
||||
enum ENUM_OFX_SIGNAL_DIRECTION {
|
||||
OFX_SIGNAL_NONE = 0,
|
||||
OFX_SIGNAL_BUY = 1,
|
||||
OFX_SIGNAL_SELL = 2,
|
||||
OFX_SIGNAL_BOTH = 3
|
||||
};
|
||||
|
||||
class CSignalBase : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
//// Replaced
|
||||
ENUM_OFX_SIGNAL_DIRECTION mSignalValues[2];
|
||||
////ENUM_OFX_SIGNAL_DIRECTION mEntrySignal;
|
||||
////ENUM_OFX_SIGNAL_DIRECTION mExitSignal;
|
||||
SIndicatorItem mIndicatorList[];
|
||||
|
||||
public: // constructors
|
||||
|
||||
CSignalBase() : CCommonBase()
|
||||
{ Init(); }
|
||||
CSignalBase(string symbol, ENUM_TIMEFRAMES timeframe) : CCommonBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CSignalBase() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual void UpdateSignal() { return; }
|
||||
//// Changed - maintain backward compatibility
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION EntrySignal() { return(mSignalValues[OFX_ENTRY_SIGNAL]); }
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION ExitSignal() { return(mSignalValues[OFX_EXIT_SIGNAL]); }
|
||||
//// New, and shows my lack of planning
|
||||
virtual void SetSignal(ENUM_OFX_SIGNAL_TYPE type,
|
||||
ENUM_OFX_SIGNAL_DIRECTION value)
|
||||
{ mSignalValues[type] = value; }
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION GetSignal(ENUM_OFX_SIGNAL_TYPE type)
|
||||
{ return(mSignalValues[type]); }
|
||||
|
||||
virtual void AddIndicator(CIndicatorBase *indicator, int bufferNum);
|
||||
virtual double GetIndicatorData(int indicatorNum, int index);
|
||||
|
||||
};
|
||||
|
||||
int CSignalBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
//// Replaced
|
||||
ArrayInitialize(mSignalValues, OFX_SIGNAL_NONE);
|
||||
////mEntrySignal = OFX_SIGNAL_NONE;
|
||||
////mExitSignal = OFX_SIGNAL_NONE;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
void CSignalBase::AddIndicator(CIndicatorBase *indicator, int bufferNum) {
|
||||
|
||||
SIndicatorItem indicatorItem = {NULL, 0};
|
||||
indicatorItem.indicator = indicator;
|
||||
indicatorItem.bufferNum = bufferNum;
|
||||
int cnt = ArraySize(mIndicatorList);
|
||||
ArrayResize(mIndicatorList, cnt+1);
|
||||
mIndicatorList[cnt] = indicatorItem;
|
||||
if (indicator.InitResult()!=INIT_SUCCEEDED) {
|
||||
InitError("",indicator.InitResult());
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
double CSignalBase::GetIndicatorData(int indicatorNum,int index) {
|
||||
|
||||
return(mIndicatorList[indicatorNum].indicator.GetData(mIndicatorList[indicatorNum].bufferNum, index));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
TPSLBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "Signalbase.mqh"
|
||||
|
||||
class CTPSLBase : public CSignalBase {
|
||||
|
||||
private:
|
||||
|
||||
public: // constructors
|
||||
|
||||
CTPSLBase() : CSignalBase() { Init(); }
|
||||
CTPSLBase(string symbol, ENUM_TIMEFRAMES timeframe) : CSignalBase(symbol, timeframe) { Init(); }
|
||||
~CTPSLBase() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual double GetTakeProfit() { return(0.0); }
|
||||
virtual double GetStopLoss() { return(0.0); }
|
||||
|
||||
};
|
||||
|
||||
int CTPSLBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __MQL4__
|
||||
#include "Trade_mql4.mqh"
|
||||
#endif
|
||||
#ifdef __MQL5__
|
||||
#include "Trade_mql5.mqh"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
(For MQL4)
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "..\CommonBase.mqh"
|
||||
|
||||
struct MqlTradeRequest {
|
||||
int action; // Trade operation type (as int here)
|
||||
ulong magic; // Expert Advisor ID (magic number)
|
||||
ulong order; // Order ticket
|
||||
string symbol; // Trade symbol
|
||||
double volume; // Requested volume for a deal in lots
|
||||
double price; // Price
|
||||
double stoplimit; // StopLimit level of the order
|
||||
double sl; // Stop Loss level of the order
|
||||
double tp; // Take Profit level of the order
|
||||
ulong deviation; // Maximal possible deviation from the requested price
|
||||
ENUM_ORDER_TYPE type; // Order type
|
||||
int type_filling; // Order execution type (int here)
|
||||
int type_time; // Order expiration type (int here)
|
||||
datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type)
|
||||
string comment; // Order comment
|
||||
ulong position; // Position ticket
|
||||
ulong position_by; // The ticket of an opposite position
|
||||
};
|
||||
|
||||
enum ENUM_POSITION_TYPE {
|
||||
POSITION_TYPE_BUY = ORDER_TYPE_BUY,
|
||||
POSITION_TYPE_SELL = ORDER_TYPE_SELL
|
||||
};
|
||||
|
||||
class CTradeCustom : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
int mMagic; // expert magic number
|
||||
|
||||
public: // constructors
|
||||
|
||||
CTradeCustom();
|
||||
~CTradeCustom();
|
||||
|
||||
public:
|
||||
|
||||
ulong RequestMagic() { return(mMagic); }
|
||||
void SetExpertMagicNumber(const int magic) { mMagic=magic; }
|
||||
|
||||
double BuyPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_ASK)); }
|
||||
double SellPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_BID)); }
|
||||
|
||||
bool Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
|
||||
bool 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="");
|
||||
|
||||
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const int deviation=ULONG_MAX);
|
||||
////New
|
||||
void PositionCountByType(const string symbol, int &count[]);
|
||||
|
||||
};
|
||||
|
||||
CTradeCustom::CTradeCustom() {
|
||||
|
||||
mMagic = 0;
|
||||
|
||||
}
|
||||
|
||||
CTradeCustom::~CTradeCustom() {
|
||||
|
||||
}
|
||||
|
||||
bool CTradeCustom::Buy(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 = BuyPrice(symbol);
|
||||
int ticket = OrderSend(symbol, ORDER_TYPE_BUY, volume, price, 0, sl, tp, comment, mMagic);
|
||||
return(ticket>0);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Trade.mqh
|
||||
(For MQL5)
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
CommonBase.mqh
|
||||
For framework version 1.0
|
||||
|
||||
*/
|
||||
|
||||
#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);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,851 @@
|
||||
/*
|
||||
ExpertBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
#include "Trade/Trade.mqh"
|
||||
#include "../Extensions/AllGridExtensions.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CExpertBase : public CCommonBase
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
int mMagicNumber;
|
||||
string mTradeComment;
|
||||
|
||||
double mVolume;
|
||||
|
||||
int GridNumber;
|
||||
int mGridGap;
|
||||
int mSlippage;
|
||||
double mDefaultLotSize;
|
||||
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_OFX_SIGNAL_TYPE
|
||||
{
|
||||
OFX_ENTRY_SIGNAL,
|
||||
OFX_EXIT_SIGNAL
|
||||
};
|
||||
|
||||
ENUM_OFX_SIGNAL_TYPE signalType;
|
||||
|
||||
enum ENUM_OFX_SIGNAL_DIRECTION
|
||||
{
|
||||
OFX_SIGNAL_NONE = 0,
|
||||
OFX_SIGNAL_BUY = 1,
|
||||
OFX_SIGNAL_SELL = 2,
|
||||
OFX_SIGNAL_BOTH = 3,
|
||||
OFX_SIGNAL_ALL = 4
|
||||
};
|
||||
|
||||
ENUM_OFX_SIGNAL_DIRECTION entrySignal;
|
||||
ENUM_OFX_SIGNAL_DIRECTION exitSignal;
|
||||
|
||||
datetime mLastBarTime;
|
||||
datetime mBarTime;
|
||||
|
||||
bool mResetGrid;
|
||||
|
||||
////Changed
|
||||
// Arrays to hold the signal objects
|
||||
CSignalGrid *mEntrySignals[];
|
||||
CSignalGrid *mExitSignals[];
|
||||
////CSignalBase *mEntrySignal;
|
||||
////CSignalBase *mExitSignal;
|
||||
|
||||
double mTakeProfitValue;
|
||||
double mStopLossValue;
|
||||
GridTPSL *mTakeProfitObj;
|
||||
GridTPSL *mStopLossObj;
|
||||
|
||||
CTradeCustom Trade;
|
||||
|
||||
private:
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool LoopMain(bool newBar, bool firstTime);
|
||||
virtual void GetPendingOrderPrice(ENUM_OFX_SIGNAL_DIRECTION tradeType);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
virtual void SetGridNumber(int gNumber) {GridNumber = gNumber;}
|
||||
virtual void SetGridGap(int gGap) {mGridGap = gGap;}
|
||||
virtual void SetResetGrid() {mResetGrid = true;}
|
||||
virtual void SetSlippage(int slippage) {mSlippage = slippage;}
|
||||
virtual void SetDefaultLotSize(double defaultLotSize) {mDefaultLotSize = defaultLotSize;}
|
||||
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;}
|
||||
virtual void SetRiskDefaultSize(ENUM_RISK_DEFAULT_SIZE riskDefaultSize) { mRiskDefaultSize = riskDefaultSize;}
|
||||
virtual void SetRiskBase(ENUM_RISK_BASE riskBase) {mRiskBase=riskBase;}
|
||||
|
||||
public: // Setup
|
||||
|
||||
////Changed
|
||||
virtual void AddEntrySignal(CSignalGrid *signal) { AddSignal(signal, mEntrySignals); }
|
||||
virtual void AddExitSignal(CSignalGrid *signal) { AddSignal(signal, mExitSignals); }
|
||||
virtual void AddSignal(CSignalGrid *signal, CSignalGrid* &signals[]);
|
||||
virtual void LotSize(double SL);
|
||||
virtual void TradeWatcher();
|
||||
virtual bool IsTradingTime();
|
||||
virtual bool CheckTradingSession();
|
||||
|
||||
////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(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;}
|
||||
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
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);
|
||||
|
||||
TradeWatcher();
|
||||
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);****/
|
||||
|
||||
|
||||
Print("entrySignal ", entrySignal, ", exitSignal ", exitSignal);
|
||||
|
||||
//
|
||||
// Should a trade be opened
|
||||
//
|
||||
MqlTradeRequest request = {}; // Just initialising
|
||||
|
||||
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);
|
||||
double AskPrice = SymbolInfoDouble(mSymbol,SYMBOL_ASK);
|
||||
double BidPrice = SymbolInfoDouble(mSymbol,SYMBOL_BID);
|
||||
bool retry = true;
|
||||
|
||||
|
||||
//GetMarketPrices(ORDER_TYPE_BUY, request);
|
||||
|
||||
|
||||
//GetMarketPrices(ORDER_TYPE_SELL_STOP, request);
|
||||
sellPrice = BidPrice - TakeProfitPoint;
|
||||
buyPrice = AskPrice + TakeProfitPoint;
|
||||
if(entrySignal==OFX_SIGNAL_BOTH)
|
||||
{
|
||||
request.price = NormalizeDouble(sellPrice, mDigits);
|
||||
|
||||
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(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");
|
||||
|
||||
//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(entrySignal==OFX_SIGNAL_SELL)
|
||||
{
|
||||
Print("Trying to open a sell");
|
||||
|
||||
//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(exitSignal==OFX_SIGNAL_ALL)
|
||||
{
|
||||
Trade.OrderCloseAll();
|
||||
Trade.PositionCloseAll();
|
||||
}
|
||||
|
||||
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();
|
||||
double sellPrice, buyPrice;
|
||||
|
||||
Trade.SetExpertMagicNumber(mMagicNumber);
|
||||
if(orderType==ORDER_TYPE_BUY)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
////New
|
||||
void CExpertBase::AddSignal(CSignalGrid *signal, CSignalGrid* &signals[])
|
||||
{
|
||||
|
||||
int index = ArraySize(signals);
|
||||
ArrayResize(signals, index+1);
|
||||
signals[index] = signal;
|
||||
|
||||
}
|
||||
|
||||
////New
|
||||
/*ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalGrid* &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; i<index; i++)
|
||||
{
|
||||
|
||||
if(result==OFX_SIGNAL_NONE)
|
||||
return(result);
|
||||
|
||||
signals[i].UpdateSignal();
|
||||
r2 = signals[i].GetSignal(signalType);
|
||||
|
||||
// The logic here
|
||||
// If the current result is both then just update to the r2
|
||||
// because this allows for any value
|
||||
// If r2 is both then this just leave the current result as is
|
||||
// Last test, meaning result is already none or buy or sell
|
||||
// If r2 is different then we cannot combine them
|
||||
// so the result must be none
|
||||
//
|
||||
// or like this
|
||||
//
|
||||
// result r2 gives
|
||||
// Both + Any = Any
|
||||
// Any + Both = Any
|
||||
// !Both + !Same = None
|
||||
if(result==OFX_SIGNAL_BOTH)
|
||||
{
|
||||
result = r2;
|
||||
}
|
||||
else
|
||||
if(r2==OFX_SIGNAL_BOTH) { }
|
||||
else
|
||||
if(result!=r2)
|
||||
{
|
||||
result = OFX_SIGNAL_NONE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(result);
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::CheckTradingSession()
|
||||
{
|
||||
string candles_times;
|
||||
int time_to_string;
|
||||
ushort a;
|
||||
string result[];
|
||||
//--- Get the separator code
|
||||
a = StringGetCharacter(":",0);
|
||||
candles_times = TimeToString(iTime(Symbol(),_Period,0), TIME_MINUTES);
|
||||
time_to_string = StringSplit(candles_times, a, result);
|
||||
|
||||
//Implement this later
|
||||
/*
|
||||
if(InpUseTradingSession)
|
||||
{
|
||||
if(InpTradingSession == LONDON_SESSION && londonSession[0] <= result[0] && londonSession[1] >= result[0])
|
||||
{
|
||||
londonSession
|
||||
}
|
||||
return;
|
||||
}*/
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::IsTradingTime(void)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if(mUseTradingSession)
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void CExpertBase::LotSize(double SL=0)
|
||||
{
|
||||
|
||||
//Lot Size Calculator
|
||||
|
||||
//If the position size is dynamic
|
||||
if(mRiskDefaultSize==RISK_DEFAULT_AUTO)
|
||||
{
|
||||
//If the stop loss is not zero then calculate the lot size
|
||||
Print("Stop loss ", SL);
|
||||
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(mSymbol,SYMBOL_TRADE_TICK_VALUE);
|
||||
Print("Tick value ", TickValue);
|
||||
//Define the base for the risk calculation depending on the parameter chosen
|
||||
if(mRiskBase==RISK_BASE_BALANCE)
|
||||
RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
if(mRiskBase==RISK_BASE_EQUITY)
|
||||
RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY);
|
||||
if(mRiskBase==RISK_BASE_FREEMARGIN)
|
||||
RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN);
|
||||
|
||||
//Calculate the Position Size
|
||||
mVolume=((RiskBaseAmount*mMaxRiskPerTrade/100)/(SL*TickValue));
|
||||
Print("Volume ", mVolume);
|
||||
}
|
||||
//If the stop loss is zero then the lot size is the default one
|
||||
if(SL==0)
|
||||
{
|
||||
mVolume=mDefaultLotSize;
|
||||
}
|
||||
}
|
||||
//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size
|
||||
mVolume=MathFloor(mVolume/SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_STEP);
|
||||
|
||||
//Limit the lot size in case it is greater than the maximum allowed by the user
|
||||
if(mVolume>mMaxLotSize)
|
||||
mVolume=mMaxLotSize;
|
||||
//Limit the lot size in case it is greater than the maximum allowed by the broker
|
||||
if(mVolume>SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MAX))
|
||||
mVolume=SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MAX);
|
||||
Print("Lot ", mVolume, " Max lot ", SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MAX));
|
||||
//If the lot size is too small then set it to 0 and don't trade
|
||||
if(mVolume<mMinLotSize || mVolume < SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MIN))
|
||||
{
|
||||
mVolume=0;
|
||||
Print("Lot size too small : ", mVolume);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
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 realOCountBuy, realOCountSell;
|
||||
|
||||
lastBuyOrderPrice = 0.0;
|
||||
lastSellOrderPrice = 0.0;
|
||||
openedBuyPositionPrice = 0.0;
|
||||
openedSellPositionPrice = 0.0;
|
||||
|
||||
ulong ticket;
|
||||
entrySignal = OFX_SIGNAL_NONE;
|
||||
exitSignal = OFX_SIGNAL_NONE;
|
||||
|
||||
//If there're many positions and account balance is negative
|
||||
|
||||
Print("There is ", PositionsTotal(), " opened positions");
|
||||
if(PositionsTotal() > 0)
|
||||
{
|
||||
//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)
|
||||
{
|
||||
if(pCountBuy == 0)
|
||||
{
|
||||
openedBuyPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
}
|
||||
|
||||
pCountBuy += 1;
|
||||
}
|
||||
|
||||
Print("POSITION_SYMBOL ", PositionGetString(POSITION_SYMBOL), " = ", mSymbol, " POSITION_TYPE ",PositionGetInteger(POSITION_TYPE), " = ", POSITION_TYPE_SELL, " Magic ", PositionGetInteger(POSITION_MAGIC), " = ",mMagicNumber);
|
||||
if(PositionGetString(POSITION_SYMBOL)==mSymbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL
|
||||
&& PositionGetInteger(POSITION_MAGIC)==mMagicNumber)
|
||||
{
|
||||
if(pCountSell == 0)
|
||||
{
|
||||
openedSellPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
}
|
||||
|
||||
pCountSell += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print(GetLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
//Count the orders by type
|
||||
|
||||
int cntO = OrdersTotal();
|
||||
|
||||
Print("Total pending orders ", cntO);
|
||||
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)==mMagicNumber)
|
||||
{
|
||||
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 ", mMagicNumber);
|
||||
if(OrderGetString(ORDER_SYMBOL)==mSymbol && OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP
|
||||
&& OrderGetInteger(ORDER_MAGIC)==mMagicNumber)
|
||||
{
|
||||
oCountSell += 1;
|
||||
lastSellOrderPrice = OrderGetDouble(ORDER_PRICE_OPEN);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
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(" 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;
|
||||
realOCountSell = pCountBuy*2;
|
||||
totalBuy = pCountBuy+oCountBuy;
|
||||
totalSell = pCountSell+oCountSell;
|
||||
realTotalBuy = pCountSell+1;
|
||||
realTotalSell = pCountBuy+1;
|
||||
|
||||
Print("Sell order (", oCountSell, ") Real (", realOCountSell, ")");
|
||||
Print("Buy order (", oCountBuy, ") Real (", realOCountBuy, ")", " Opened sell ", pCountSell);
|
||||
|
||||
|
||||
Print("oCountSell ", oCountSell, " < ", " realOCountSell ", realOCountSell, " && ", " pCountBuy ", pCountBuy," > 0");
|
||||
|
||||
if(OrdersTotal() == 0 && PositionsTotal() == 0)
|
||||
{
|
||||
entrySignal = OFX_SIGNAL_BOTH;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//If there's only one pending order left, close it.
|
||||
if(OrdersTotal() >= 1 && PositionsTotal() == 0)
|
||||
{
|
||||
exitSignal = OFX_SIGNAL_ALL;
|
||||
Print("Exit if no opened position");
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
{
|
||||
//If there's only one pending order left, close it.
|
||||
if(OrdersTotal() >= 1 && PositionsTotal() == 0)
|
||||
{
|
||||
exitSignal = OFX_SIGNAL_ALL;
|
||||
Print("Exit if no opened position");
|
||||
}
|
||||
else
|
||||
{
|
||||
//When there are multiple positions, check is the account is making enough profit
|
||||
Print("floatingProfitPercent ", floatingProfitPercent, " mMaxRiskPerTrade ", mMaxRiskPerTrade);
|
||||
if(floatingProfitPercent > mProfitPercent)
|
||||
{
|
||||
exitSignal = OFX_SIGNAL_ALL;
|
||||
Print("Exit on profit target");
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("realTotalSell ", realTotalSell, " <= ", " totalSell ", totalSell," && ", " pCountBuy ",pCountBuy," > 0");
|
||||
if(realTotalSell > totalSell && pCountBuy > 0)
|
||||
{
|
||||
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, ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
/*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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Framework_2.03.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// History
|
||||
// 1.00 - First version, not well version controlled
|
||||
// 2.00 - Changed framework structure, functionally same as 1.00
|
||||
// 2.01 - Added TP and SL
|
||||
// 2.02 - Move compound signals into expertbase
|
||||
// Templates now use common files between mq4 and mq5
|
||||
// MakeMQH batch script also recreates framework.mqh
|
||||
// 2.03 - Added macros to CommonBase to standardise init checking
|
||||
// Moved base classes up one level and removed unnecessary folders
|
||||
|
||||
#ifndef _FRAMEWORK_VERSION_
|
||||
|
||||
#define _FRAMEWORK_VERSION_ "2.03"
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
|
||||
#include "Trade/Trade.mqh"
|
||||
|
||||
#include "SignalBase.mqh"
|
||||
#include "TPSLBase.mqh"
|
||||
|
||||
#include "ExpertBase.mqh"
|
||||
|
||||
#include "../Extensions/AllGridExtensions.mqh"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
IndicatorBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
|
||||
class CIndicatorBase : public CCommonBase {
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
// Only used for MQL5
|
||||
int mIndicatorHandle;
|
||||
|
||||
public: // constructors
|
||||
|
||||
CIndicatorBase() : CCommonBase()
|
||||
{ Init(); }
|
||||
CIndicatorBase(string symbol, ENUM_TIMEFRAMES timeframe)
|
||||
: CCommonBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CIndicatorBase();
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual double GetData(const int index) { return(GetData(0,index)); }
|
||||
virtual double GetData(const int bufferNum, const int index){ return (0); }
|
||||
|
||||
};
|
||||
|
||||
CIndicatorBase::~CIndicatorBase() {
|
||||
|
||||
#ifdef __MQL5__
|
||||
|
||||
if (mIndicatorHandle!=INVALID_HANDLE) IndicatorRelease(mIndicatorHandle);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int CIndicatorBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
mIndicatorHandle = INVALID_HANDLE;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
SignalBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "CommonBase.mqh"
|
||||
//#include "IndicatorBase.mqh"
|
||||
|
||||
//// New
|
||||
//// This is to maintain compatibility and allow sub classes to still
|
||||
//// use mEntrySignal= or mExitSignal=
|
||||
//// mEntrySignal and mExitSignal are effectively deprecated now
|
||||
#define mEntrySignal mSignalValues[OFX_ENTRY_SIGNAL] // Deprecated
|
||||
#define mExitSignal mSignalValues[OFX_EXIT_SIGNAL] // Deprecated
|
||||
|
||||
|
||||
//// New
|
||||
enum ENUM_OFX_SIGNAL_TYPE
|
||||
{
|
||||
OFX_ENTRY_SIGNAL,
|
||||
OFX_EXIT_SIGNAL
|
||||
};
|
||||
|
||||
enum ENUM_OFX_SIGNAL_DIRECTION
|
||||
{
|
||||
OFX_SIGNAL_NONE = 0,
|
||||
OFX_SIGNAL_BUY = 1,
|
||||
OFX_SIGNAL_SELL = 2,
|
||||
OFX_SIGNAL_BOTH = 3,
|
||||
OFX_SIGNAL_ALL = 4
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalBase : public CCommonBase
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
protected: // member variables
|
||||
|
||||
//// Replaced
|
||||
ENUM_OFX_SIGNAL_DIRECTION mSignalValues[2];
|
||||
double mMaxRiskPerTrade;
|
||||
////ENUM_OFX_SIGNAL_DIRECTION mEntrySignal;
|
||||
////ENUM_OFX_SIGNAL_DIRECTION mExitSignal;
|
||||
|
||||
public: // constructors
|
||||
|
||||
CSignalBase() : CCommonBase()
|
||||
{ Init(); }
|
||||
CSignalBase(string symbol, ENUM_TIMEFRAMES timeframe) : CCommonBase(symbol, timeframe)
|
||||
{ Init(); }
|
||||
~CSignalBase() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual void UpdateSignal() { return; }
|
||||
//// Changed - maintain backward compatibility
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION EntrySignal() { return(mSignalValues[OFX_ENTRY_SIGNAL]); }
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION ExitSignal() { return(mSignalValues[OFX_EXIT_SIGNAL]); }
|
||||
//// New, and shows my lack of planning
|
||||
virtual void SetSignal(ENUM_OFX_SIGNAL_TYPE type,
|
||||
ENUM_OFX_SIGNAL_DIRECTION value)
|
||||
{ mSignalValues[type] = value; }
|
||||
virtual void SetMaxRiskPerTrade(double maxRiskPerTrade) { mMaxRiskPerTrade = maxRiskPerTrade;}
|
||||
|
||||
virtual ENUM_OFX_SIGNAL_DIRECTION GetSignal(ENUM_OFX_SIGNAL_TYPE type)
|
||||
{ return(mSignalValues[type]); }
|
||||
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalBase::Init()
|
||||
{
|
||||
|
||||
if(InitResult()!=INIT_SUCCEEDED)
|
||||
return(InitResult());
|
||||
|
||||
//// Replaced
|
||||
ArrayInitialize(mSignalValues, OFX_SIGNAL_NONE);
|
||||
////mEntrySignal = OFX_SIGNAL_NONE;
|
||||
////mExitSignal = OFX_SIGNAL_NONE;
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
TPSLBase.mqh
|
||||
|
||||
Copyright 2013-2020, Orchard Forex
|
||||
https://www.orchardforex.com
|
||||
|
||||
*/
|
||||
|
||||
#include "Signalbase.mqh"
|
||||
|
||||
class CTPSLBase : public CSignalBase {
|
||||
|
||||
private:
|
||||
|
||||
public: // constructors
|
||||
|
||||
CTPSLBase() : CSignalBase() { Init(); }
|
||||
CTPSLBase(string symbol, ENUM_TIMEFRAMES timeframe) : CSignalBase(symbol, timeframe) { Init(); }
|
||||
~CTPSLBase() { }
|
||||
|
||||
int Init();
|
||||
|
||||
public:
|
||||
|
||||
virtual double GetTakeProfit() { return(0.0); }
|
||||
virtual double GetStopLoss() { return(0.0); }
|
||||
|
||||
};
|
||||
|
||||
int CTPSLBase::Init() {
|
||||
|
||||
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user