624 lines
19 KiB
MQL5
624 lines
19 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| ProjectName |
| |
//| Copyright 2020, CompanyName |
| |
//| http://www.companyname.net |
| |
//+------------------------------------------------------------------+
| |
| |
| |
#include <errordescription.mqh>
| |
#include "Trade.mqh"
| |
| |
enum Signal
| |
{
| |
SIGNAL_BUY,
| |
SIGNAL_SELL,
| |
SIGNAL_NONE,
| |
| |
};
| |
| |
string tradeResponse = "";
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
class CTradeHedge : public CTrade
| |
{
| |
protected:
| |
ulong OpenPosition(string pSymbol, ENUM_ORDER_TYPE pType, double pVolume, double pStop = 0, double pProfit = 0, string pComment = "Concrete Goonies");
| |
string orderType;
| |
public:
| |
ulong Buy(string pSymbol, double pVolume, double pStop = 0, double pProfit = 0, string pComment = NULL);
| |
ulong Sell(string pSymbol, double pVolume, double pStop = 0, double pProfit = 0, string pComment = NULL);
| |
| |
bool ModifyPosition(ulong pTicket, double pStop, double pProfit = 0);
| |
bool Close(ulong pTicket, double pVolume = 0, string pComment = NULL);
| |
};
| |
| |
| |
// Open position
| |
ulong CTradeHedge::OpenPosition(string pSymbol, ENUM_ORDER_TYPE pType, double pVolume, double pStop = 0, double pProfit = 0, string pComment = "Concrete Goonies")
| |
{
| |
ZeroMemory(request);
| |
ZeroMemory(result);
| |
| |
request.action = TRADE_ACTION_DEAL;
| |
request.symbol = pSymbol;
| |
request.type = pType;
| |
request.sl = pStop;
| |
request.tp = pProfit;
| |
request.comment =pComment ;
| |
request.volume = pVolume;
| |
request.deviation = deviation;
| |
request.type_filling = fillType;
| |
request.magic = magicNumber;
| |
| |
int retryCount = -1;
| |
int checkCode = 0;
| |
| |
Print(SymbolInfoDouble(pSymbol, SYMBOL_ASK));
| |
do
| |
{
| |
if(pType == ORDER_TYPE_BUY)
| |
{
| |
request.price = SymbolInfoDouble(pSymbol, SYMBOL_ASK);
| |
| |
}
| |
else
| |
if(pType == ORDER_TYPE_SELL)
| |
request.price = SymbolInfoDouble(pSymbol, SYMBOL_BID);
| |
| |
bool sent = OrderSend(request, result);
| |
| |
checkCode = CheckReturnCode(result.retcode);
| |
| |
if(checkCode == CHECK_RETCODE_OK)
| |
break;
| |
else
| |
if(checkCode == CHECK_RETCODE_ERROR)
| |
{
| |
string errDesc = TradeServerReturnCodeDescription(result.retcode);
| |
Alert("Open market order: Error ", result.retcode, " - ", errDesc);
| |
tradeResponse = "";
| |
LogTradeRequest();
| |
break;
| |
}
| |
else
| |
{
| |
Print("Server error detected, retrying...");
| |
Sleep(RETRY_DELAY);
| |
retryCount++;
| |
}
| |
}
| |
while(retryCount < MAX_RETRIES);
| |
| |
if(retryCount >= MAX_RETRIES)
| |
{
| |
string errDesc = TradeServerReturnCodeDescription(result.retcode);
| |
Alert("Max retries exceeded: Error ", result.retcode, " - ", errDesc);
| |
}
| |
| |
string orderType = CheckOrderType(pType);
| |
string errDesc = TradeServerReturnCodeDescription(result.retcode);
| |
| |
//Print("Open ",orderType," order #",result.order,": ",result.retcode," - ",errDesc,", Volume: ",result.volume,", Price: ",result.price);
| |
| |
if(checkCode == CHECK_RETCODE_OK)
| |
{
| |
//Comment(orderType," position #",result.order," opened at ",result.price," on ",pSymbol);
| |
return(result.order);
| |
}
| |
else
| |
return(0);
| |
}
| |
| |
| |
// Modify position
| |
bool CTradeHedge::ModifyPosition(ulong pTicket, double pStop, double pProfit = 0)
| |
{
| |
ZeroMemory(request);
| |
ZeroMemory(result);
| |
| |
bool select = PositionSelectByTicket(pTicket);
| |
string symbol = PositionGetString(POSITION_SYMBOL);
| |
double price = PositionGetDouble(POSITION_PRICE_OPEN);
| |
| |
request.action = TRADE_ACTION_SLTP;
| |
request.sl = pStop;
| |
request.tp = pProfit;
| |
request.position = pTicket;
| |
request.symbol = symbol;
| |
| |
// Order loop
| |
int retryCount = 0;
| |
int checkCode = 0;
| |
| |
do
| |
{
| |
bool sent = OrderSend(request, result);
| |
| |
checkCode = CheckReturnCode(result.retcode);
| |
| |
if(checkCode == CHECK_RETCODE_OK)
| |
break;
| |
else
| |
if(checkCode == CHECK_RETCODE_ERROR)
| |
{
| |
string errDesc = TradeServerReturnCodeDescription(result.retcode);
| |
//Comment("Modify position: Error ",result.retcode," - ",errDesc);
| |
LogTradeRequest();
| |
break;
| |
}
| |
else
| |
{
| |
Print("Server error detected, retrying...");
| |
Sleep(RETRY_DELAY);
| |
retryCount++;
| |
}
| |
}
| |
while(retryCount < MAX_RETRIES);
| |
| |
if(retryCount >= MAX_RETRIES)
| |
{
| |
string errDesc = TradeServerReturnCodeDescription(result.retcode);
| |
Alert("Max retries exceeded: Error ", result.retcode, " - ", errDesc);
| |
}
| |
| |
string errDesc = TradeServerReturnCodeDescription(result.retcode);
| |
//Print("Modify position #",pTicket,": ",result.retcode," - ",errDesc,", SL: ",request.sl,", TP: ",request.tp,", Bid: ",SymbolInfoDouble(symbol,SYMBOL_BID),", Ask: ",SymbolInfoDouble(symbol,SYMBOL_ASK),", Stop Level: ",SymbolInfoInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL));
| |
| |
double pi_8 = NormalizeDouble(price, _Digits);
| |
double pi_11 = NormalizeDouble(request.sl, _Digits);
| |
double pi_10 = NormalizeDouble(request.tp, _Digits);
| |
long posType = PositionGetInteger(POSITION_TYPE);
| |
| |
| |
if(posType == POSITION_TYPE_BUY)
| |
{
| |
orderType = "Buy";
| |
}
| |
else
| |
if(posType == POSITION_TYPE_SELL)
| |
{
| |
orderType = "Sell";
| |
}
| |
if(checkCode == CHECK_RETCODE_OK)
| |
{
| |
Alert(orderType, " - Price: ", DoubleToString(pi_8, _Digits), ", SL: ", DoubleToString(pi_11, _Digits), ", TP: ", DoubleToString(pi_10, _Digits));
| |
| |
/* open = DoubleToString(pi_8, _Digits);
| |
sl = DoubleToString(pi_11, _Digits);
| |
tp = DoubleToString(pi_10, _Digits);*/
| |
return(true);
| |
}
| |
else
| |
return(false);
| |
| |
}
| |
| |
| |
// Close position
| |
bool CTradeHedge::Close(ulong pTicket, double pVolume = 0, string pComment = NULL)
| |
{
| |
ZeroMemory(request);
| |
ZeroMemory(result);
| |
| |
request.action = TRADE_ACTION_DEAL;
| |
request.position = pTicket;
| |
request.deviation = deviation;
| |
request.type_filling = fillType;
| |
request.comment = "Concrete Goonies";
| |
double closeVol = 0;
| |
long openType = WRONG_VALUE;
| |
string symbol;
| |
| |
if(PositionSelectByTicket(pTicket) == true)
| |
{
| |
closeVol = PositionGetDouble(POSITION_VOLUME);
| |
openType = PositionGetInteger(POSITION_TYPE);
| |
symbol = PositionGetString(POSITION_SYMBOL);
| |
}
| |
else
| |
return(false);
| |
| |
request.symbol = symbol;
| |
| |
if(pVolume > closeVol || pVolume <= 0)
| |
request.volume = closeVol;
| |
else
| |
request.volume = pVolume;
| |
| |
// Order loop
| |
int retryCount = -1;
| |
int checkCode = 0;
| |
| |
do
| |
{
| |
if(openType == POSITION_TYPE_BUY)
| |
{
| |
request.type = ORDER_TYPE_SELL;
| |
request.price = SymbolInfoDouble(symbol, SYMBOL_BID);
| |
}
| |
else
| |
if(openType == POSITION_TYPE_SELL)
| |
{
| |
request.type = ORDER_TYPE_BUY;
| |
request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
| |
}
| |
| |
bool sent = OrderSend(request, result);
| |
| |
checkCode = CheckReturnCode(result.retcode);
| |
| |
if(checkCode == CHECK_RETCODE_OK)
| |
break;
| |
else
| |
if(checkCode == CHECK_RETCODE_ERROR)
| |
{
| |
string errDesc = TradeServerReturnCodeDescription(result.retcode);
| |
Alert("Close position: Error ", result.retcode, " - ", errDesc);
| |
LogTradeRequest();
| |
break;
| |
}
| |
else
| |
{
| |
Print("Server error detected, retrying...");
| |
Sleep(RETRY_DELAY);
| |
retryCount++;
| |
}
| |
}
| |
while(retryCount < MAX_RETRIES);
| |
| |
if(retryCount >= MAX_RETRIES)
| |
{
| |
string errDesc = TradeServerReturnCodeDescription(result.retcode);
| |
Alert("Max retries exceeded: Error ", result.retcode, " - ", errDesc);
| |
}
| |
| |
string posType;
| |
if(openType == POSITION_TYPE_BUY)
| |
posType = "Buy";
| |
else
| |
if(openType == POSITION_TYPE_SELL)
| |
posType = "Sell";
| |
| |
string errDesc = TradeServerReturnCodeDescription(result.retcode);
| |
//Print("Close ",posType," position #",pTicket,": ",result.retcode," - ",errDesc,", Volume: ",result.volume,", Price: ",result.price);
| |
| |
if(checkCode == CHECK_RETCODE_OK)
| |
{
| |
//Comment(posType," position closed on ",symbol," at ",result.price);
| |
return(true);
| |
}
| |
else
| |
return(false);
| |
}
| |
| |
| |
// Trade opening shortcuts
| |
ulong CTradeHedge::Buy(string pSymbol, double pVolume, double pStop , double pProfit , string pComment )
| |
{
| |
ulong ticket = OpenPosition(pSymbol, ORDER_TYPE_BUY, pVolume, pStop, pProfit, pComment);
| |
return(ticket);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
ulong CTradeHedge::Sell(string pSymbol, double pVolume, double pStop = 0, double pProfit = 0, string pComment = NULL)
| |
{
| |
ulong ticket = OpenPosition(pSymbol, ORDER_TYPE_SELL, pVolume, pStop, pProfit, pComment);
| |
return(ticket);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| Position Tickets & Counts |
| |
//+------------------------------------------------------------------+
| |
| |
| |
// Open position information
| |
class CPositions
| |
{
| |
protected:
| |
ulong BuyTickets[];
| |
ulong SellTickets[];
| |
ulong Tickets[];
| |
int BuyCount;
| |
int SellCount;
| |
int TotalCount;
| |
| |
void GetOpenPositions(ulong pMagicNumber = 0);
| |
int ResizeArray(ulong &array[]);
| |
| |
| |
public:
| |
int Buy(ulong pMagicNumber);
| |
int Sell(ulong pMagicNumber);
| |
int TotalPositions(ulong pMagicNumber);
| |
| |
void GetBuyTickets(ulong pMagicNumber, ulong &pTickets[]);
| |
void GetSellTickets(ulong pMagicNumber, ulong &pTickets[]);
| |
int GetTickets(ulong pMagicNumber, ulong &pTickets[]);
| |
};
| |
| |
// Get open positions
| |
void CPositions::GetOpenPositions(ulong pMagicNumber = 0)
| |
{
| |
BuyCount = 0;
| |
SellCount = 0;
| |
TotalCount = 0;
| |
| |
ArrayResize(BuyTickets, 17);
| |
ArrayInitialize(BuyTickets, 0);
| |
| |
ArrayResize(SellTickets, 17);
| |
ArrayInitialize(SellTickets, 0);
| |
| |
ArrayResize(Tickets, 17);
| |
ArrayInitialize(Tickets, 0);
| |
| |
for(int i = 0; i < PositionsTotal(); i++)
| |
{
| |
ulong ticket = PositionGetTicket(i);
| |
PositionSelectByTicket(ticket);
| |
| |
if(PositionGetInteger(POSITION_MAGIC) != pMagicNumber && pMagicNumber > 0)
| |
continue;
| |
| |
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
| |
{
| |
BuyCount++;
| |
int arrayIndex = ResizeArray(BuyTickets);
| |
BuyTickets[arrayIndex] = PositionGetInteger(POSITION_TICKET);
| |
}
| |
else
| |
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
| |
{
| |
SellCount++;
| |
int arrayIndex = ResizeArray(SellTickets);
| |
SellTickets[arrayIndex] = PositionGetInteger(POSITION_TICKET);
| |
}
| |
| |
TotalCount++;
| |
int arrayIndex = ResizeArray(Tickets);
| |
Tickets[arrayIndex] = PositionGetInteger(POSITION_TICKET);
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
int CPositions::ResizeArray(ulong &array[])
| |
{
| |
int arrayIndex = 0;
| |
if(ArraySize(array) > 1)
| |
{
| |
int newSize = ArrayResize(array, ArraySize(array) + 1);
| |
arrayIndex = newSize - 1;
| |
}
| |
| |
return arrayIndex;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
int CPositions::Buy(ulong pMagicNumber)
| |
{
| |
GetOpenPositions(pMagicNumber);
| |
return(BuyCount);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
int CPositions::Sell(ulong pMagicNumber)
| |
{
| |
GetOpenPositions(pMagicNumber);
| |
return(SellCount);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
int CPositions::TotalPositions(ulong pMagicNumber)
| |
{
| |
GetOpenPositions(pMagicNumber);
| |
return(TotalCount);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CPositions::GetBuyTickets(ulong pMagicNumber, ulong &pTickets[])
| |
{
| |
GetOpenPositions(pMagicNumber);
| |
ArrayCopy(pTickets, BuyTickets);
| |
return;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CPositions::GetSellTickets(ulong pMagicNumber, ulong &pTickets[])
| |
{
| |
GetOpenPositions(pMagicNumber);
| |
ArrayCopy(pTickets, SellTickets);
| |
return;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
int CPositions::GetTickets(ulong pMagicNumber, ulong &pTickets[])
| |
{
| |
GetOpenPositions(pMagicNumber);
| |
ArrayCopy(pTickets, Tickets);
| |
return(WRONG_VALUE);
| |
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| Position Information Functions |
| |
//+------------------------------------------------------------------+
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
string PositionComment(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetString(POSITION_COMMENT));
| |
else
| |
return(NULL);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
long PositionType(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetInteger(POSITION_TYPE));
| |
else
| |
return(WRONG_VALUE);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
long PositionIdentifier(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetInteger(POSITION_IDENTIFIER));
| |
else
| |
return(WRONG_VALUE);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
double PositionOpenPrice(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetDouble(POSITION_PRICE_OPEN));
| |
else
| |
return(WRONG_VALUE);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
long PositionOpenTime(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetInteger(POSITION_TIME));
| |
else
| |
return(WRONG_VALUE);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
double PositionVolume(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetDouble(POSITION_VOLUME));
| |
else
| |
return(WRONG_VALUE);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
double PositionStopLoss(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetDouble(POSITION_SL));
| |
else
| |
return(WRONG_VALUE);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
double PositionTakeProfit(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetDouble(POSITION_TP));
| |
else
| |
return(WRONG_VALUE);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
double PositionProfit(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetDouble(POSITION_PROFIT));
| |
else
| |
return(WRONG_VALUE);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
long PositionMagicNumber(ulong pTicket = 0)
| |
{
| |
bool select = false;
| |
if(pTicket > 0)
| |
select = PositionSelectByTicket(pTicket);
| |
| |
if(select == true)
| |
return(PositionGetInteger(POSITION_MAGIC));
| |
else
| |
return(NULL);
| |
}
| |
//+------------------------------------------------------------------+
|