mirror of
https://github.com/rithsila/MT5-EA-Sniper-Strategy.git
synced 2026-08-22 07:08:19 +00:00
Organize project in different folders
This commit is contained in:
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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,152 @@
|
||||
/*
|
||||
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 PositionCloseByTicket(const ulong ticket,const ulong deviation=ULONG_MAX);
|
||||
bool PositionCloseAll(const ulong deviation=ULONG_MAX);
|
||||
bool OrderCloseAll();
|
||||
|
||||
////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);
|
||||
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTradeCustom::PositionCloseByTicket(const ulong ticket,const ulong deviation=-1)
|
||||
{
|
||||
bool result = true;
|
||||
if(PositionSelectByTicket(ticket))
|
||||
{
|
||||
if(PositionGetInteger(POSITION_MAGIC)==m_magic)
|
||||
{
|
||||
result &= PositionClose(ticket, deviation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_result.retcode=TRADE_RETCODE_REJECT;
|
||||
result = false;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTradeCustom::PositionCloseAll(const ulong deviation=-1)
|
||||
{
|
||||
bool result = true;
|
||||
int cnt = PositionsTotal();
|
||||
for(int i = cnt-1; i>=0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(PositionSelectByTicket(ticket))
|
||||
{
|
||||
|
||||
result &= PositionClose(ticket, deviation);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_result.retcode=TRADE_RETCODE_REJECT;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
bool CTradeCustom::OrderCloseAll(){
|
||||
bool result = true;
|
||||
int cnt = OrdersTotal();
|
||||
for(int i = cnt-1; i>=0; i--)
|
||||
{
|
||||
ulong ticket = OrderGetTicket(i);
|
||||
if(OrderSelect(ticket))
|
||||
{
|
||||
|
||||
result &= OrderDelete(ticket);
|
||||
}
|
||||
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
|
||||
Reference in New Issue
Block a user