mql5/Include/Mql5Book/TradeHedge.mqh

624 lines
19 KiB
MQL5

2026-03-15 02:48:52 +02:00
//+------------------------------------------------------------------+
//| 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);
}
//+------------------------------------------------------------------+