286 lines
11 KiB
MQL5
286 lines
11 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| sonic |
|
|
//| Copyright 2021, NhatNamBe |
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include <Trade/Trade.mqh>
|
|
#include <Trade/AccountInfo.mqh>
|
|
#include <Trade/SymbolInfo.mqh>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int GetStepWise(ENUM_POSITION_TYPE posType)
|
|
{
|
|
return (posType==POSITION_TYPE_BUY)?1:-1;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//|Check trading account will be used for bot's operation |
|
|
//+------------------------------------------------------------------+
|
|
int CheckAccount()
|
|
{
|
|
//--- unable to trade on a real account
|
|
CAccountInfo account;
|
|
long login=account.Login();
|
|
Print("Login:", login);
|
|
ENUM_ACCOUNT_TRADE_MODE account_type=account.TradeMode();
|
|
if(account_type==ACCOUNT_TRADE_MODE_REAL)
|
|
{
|
|
Alert("Expert Advisor cannot trade on a real account!");
|
|
return(-2);
|
|
}
|
|
Print("Account type: ", EnumToString(account_type));
|
|
//--- check if it is possible to trade on this account (for example, trading is impossible when using an investor password)
|
|
if(account.TradeAllowed())
|
|
Print("Trading on this account is allowed");
|
|
else
|
|
{
|
|
Print("Trading on this account is forbidden: you may have entered using the Investor password");
|
|
return(-3);
|
|
}
|
|
//--- clarifying if we can use an Expert Advisor on this account
|
|
if(account.TradeExpert())
|
|
Print("Automated trading on this account is allowed");
|
|
else
|
|
{
|
|
Print("Automated trading using Expert Advisors and scripts on this account is forbidden");
|
|
return(-4);
|
|
}
|
|
//--- clarifying if the permissible number of orders has been set
|
|
int orders_limit=account.LimitOrders();
|
|
if(orders_limit!=0)
|
|
Print("Maximum permissible amount of active pending orders: ",orders_limit);
|
|
//--- displaying company and server names
|
|
Print(account.Company(),": server ",account.Server());
|
|
//--- displaying balance and current profit on the account in the end
|
|
Print("Balance=",account.Balance()," Profit=",account.Profit()," Equity=",account.Equity());
|
|
Print(__FUNCTION__," completed"); //---
|
|
return(0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Get properties of the symbol |
|
|
//+------------------------------------------------------------------+
|
|
void GetSymbolInfo()
|
|
{
|
|
//--- object for receiving symbol settings
|
|
CSymbolInfo symbol_info;
|
|
//--- set the name for the appropriate symbol
|
|
symbol_info.Name(_Symbol);
|
|
//--- receive current rates and display
|
|
symbol_info.RefreshRates();
|
|
Print(symbol_info.Name()," (",symbol_info.Description(),")",
|
|
" Bid=",symbol_info.Bid()," Ask=",symbol_info.Ask());
|
|
//--- receive minimum freeze levels for trade operations
|
|
Print("StopsLevel=",symbol_info.StopsLevel()," pips, FreezeLevel=",
|
|
symbol_info.FreezeLevel()," pips");
|
|
//--- receive the number of decimal places and point size
|
|
Print("Digits=",symbol_info.Digits(),
|
|
", Point=",DoubleToString(symbol_info.Point(),symbol_info.Digits()));
|
|
//--- spread info
|
|
Print("SpreadFloat=",symbol_info.SpreadFloat(),", Spread(current)=",
|
|
symbol_info.Spread()," pips");
|
|
//--- request order execution type for limitations
|
|
Print("Limitations for trade operations: ",EnumToString(symbol_info.TradeMode()),
|
|
" (",symbol_info.TradeModeDescription(),")");
|
|
//--- clarifying trades execution mode
|
|
Print("Trades execution mode: ",EnumToString(symbol_info.TradeExecution()),
|
|
" (",symbol_info.TradeExecutionDescription(),")");
|
|
//--- clarifying contracts price calculation method
|
|
Print("Contract price calculation: ",EnumToString(symbol_info.TradeCalcMode()),
|
|
" (",symbol_info.TradeCalcModeDescription(),")");
|
|
//--- sizes of contracts
|
|
Print("Standard contract size: ",symbol_info.ContractSize(),
|
|
" (",symbol_info.CurrencyBase(),")");
|
|
//--- minimum and maximum volumes in trade operations
|
|
Print("Volume info: LotsMin=",symbol_info.LotsMin()," LotsMax=",symbol_info.LotsMax(),
|
|
" LotsStep=",symbol_info.LotsStep());
|
|
//---
|
|
Print(__FUNCTION__," completed");
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Place Order |
|
|
//+------------------------------------------------------------------+
|
|
ulong PlaceOrder(const string symbol,const ENUM_POSITION_TYPE pos_type,const ENUM_ORDER_TYPE order_type,const double volume,
|
|
const double price,const double sl_value,const double tp_value,const string comment,const bool retry=true)
|
|
{
|
|
CTrade trade;
|
|
bool ret;
|
|
double TP=0;
|
|
double SL=0;
|
|
//--- number of decimal places
|
|
int digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
|
|
//--- calculate and normalize SL and TP levels
|
|
if(sl_value)
|
|
SL=NormalizeDouble(price-GetStepWise(pos_type)*sl_value,digits);
|
|
if(tp_value)
|
|
TP=NormalizeDouble(price+GetStepWise(pos_type)*tp_value,digits);
|
|
|
|
if(order_type==ORDER_TYPE_BUY || order_type==ORDER_TYPE_SELL)
|
|
ret=trade.PositionOpen(symbol,order_type,volume,price,SL,TP,comment);
|
|
else
|
|
ret=trade.OrderOpen(symbol,order_type,volume,0,price,SL,TP,ORDER_TIME_GTC,0,comment);
|
|
|
|
if(!ret)
|
|
{
|
|
if(retry)
|
|
{
|
|
//--- failed to place limit order cause price is moving to market, replace
|
|
while(!ret)
|
|
{
|
|
//--- failure message
|
|
DebugBreak();
|
|
Print("PlaceOrder() method failed. Return code=",trade.ResultRetcode(),
|
|
". Code description: ",trade.ResultRetcodeDescription());
|
|
double newPrice;
|
|
|
|
if(order_type==ORDER_TYPE_BUY || order_type==ORDER_TYPE_SELL)
|
|
//--- market order
|
|
newPrice=(pos_type==POSITION_TYPE_BUY)?SymbolInfoDouble(_Symbol,SYMBOL_ASK):SymbolInfoDouble(_Symbol,SYMBOL_BID);
|
|
else
|
|
//--- limit order
|
|
newPrice=(pos_type==POSITION_TYPE_BUY)?SymbolInfoDouble(_Symbol,SYMBOL_BID):SymbolInfoDouble(_Symbol,SYMBOL_ASK);
|
|
//--- calculate and normalize SL and TP levels
|
|
double orderPrice;
|
|
if(newPrice*GetStepWise(pos_type) < price*GetStepWise(pos_type))
|
|
orderPrice=newPrice;
|
|
else
|
|
orderPrice=price;
|
|
|
|
if(sl_value)
|
|
SL=NormalizeDouble(orderPrice-GetStepWise(pos_type)*sl_value,digits);
|
|
if(tp_value)
|
|
TP=NormalizeDouble(orderPrice+GetStepWise(pos_type)*sl_value,digits);
|
|
if(order_type==ORDER_TYPE_BUY || order_type==ORDER_TYPE_SELL)
|
|
ret=trade.PositionOpen(symbol,order_type,volume,orderPrice,SL,TP,comment);
|
|
else
|
|
ret=trade.OrderOpen(symbol,order_type,volume,0,orderPrice,SL,TP,ORDER_TIME_GTC,0,comment);
|
|
}
|
|
Print("PlaceOrder() method executed successfully order ticket: ",trade.ResultOrder(),". Return code=",trade.ResultRetcode(),
|
|
" (",trade.ResultRetcodeDescription(),")");
|
|
return(trade.ResultOrder());
|
|
}
|
|
else
|
|
{
|
|
//--- failure message
|
|
Print("PlaceOrder() method failed. Return code=",trade.ResultRetcode(),
|
|
". Code description: ",trade.ResultRetcodeDescription());
|
|
return(-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Print("PlaceOrder() method executed successfully order ticket: ",trade.ResultOrder(),". Return code=",trade.ResultRetcode(),
|
|
" (",trade.ResultRetcodeDescription(),")");
|
|
return(trade.ResultOrder());
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| convert numeric response codes to string mnemonics |
|
|
//+------------------------------------------------------------------+
|
|
string GetRetcodeID(int retcode)
|
|
{
|
|
switch(retcode)
|
|
{
|
|
case 10004:
|
|
return("TRADE_RETCODE_REQUOTE");
|
|
break;
|
|
case 10006:
|
|
return("TRADE_RETCODE_REJECT");
|
|
break;
|
|
case 10007:
|
|
return("TRADE_RETCODE_CANCEL");
|
|
break;
|
|
case 10008:
|
|
return("TRADE_RETCODE_PLACED");
|
|
break;
|
|
case 10009:
|
|
return("TRADE_RETCODE_DONE");
|
|
break;
|
|
case 10010:
|
|
return("TRADE_RETCODE_DONE_PARTIAL");
|
|
break;
|
|
case 10011:
|
|
return("TRADE_RETCODE_ERROR");
|
|
break;
|
|
case 10012:
|
|
return("TRADE_RETCODE_TIMEOUT");
|
|
break;
|
|
case 10013:
|
|
return("TRADE_RETCODE_INVALID");
|
|
break;
|
|
case 10014:
|
|
return("TRADE_RETCODE_INVALID_VOLUME");
|
|
break;
|
|
case 10015:
|
|
return("TRADE_RETCODE_INVALID_PRICE");
|
|
break;
|
|
case 10016:
|
|
return("TRADE_RETCODE_INVALID_STOPS");
|
|
break;
|
|
case 10017:
|
|
return("TRADE_RETCODE_TRADE_DISABLED");
|
|
break;
|
|
case 10018:
|
|
return("TRADE_RETCODE_MARKET_CLOSED");
|
|
break;
|
|
case 10019:
|
|
return("TRADE_RETCODE_NO_MONEY");
|
|
break;
|
|
case 10020:
|
|
return("TRADE_RETCODE_PRICE_CHANGED");
|
|
break;
|
|
case 10021:
|
|
return("TRADE_RETCODE_PRICE_OFF");
|
|
break;
|
|
case 10022:
|
|
return("TRADE_RETCODE_INVALID_EXPIRATION");
|
|
break;
|
|
case 10023:
|
|
return("TRADE_RETCODE_ORDER_CHANGED");
|
|
break;
|
|
case 10024:
|
|
return("TRADE_RETCODE_TOO_MANY_REQUESTS");
|
|
break;
|
|
case 10025:
|
|
return("TRADE_RETCODE_NO_CHANGES");
|
|
break;
|
|
case 10026:
|
|
return("TRADE_RETCODE_SERVER_DISABLES_AT");
|
|
break;
|
|
case 10027:
|
|
return("TRADE_RETCODE_CLIENT_DISABLES_AT");
|
|
break;
|
|
case 10028:
|
|
return("TRADE_RETCODE_LOCKED");
|
|
break;
|
|
case 10029:
|
|
return("TRADE_RETCODE_FROZEN");
|
|
break;
|
|
case 10030:
|
|
return("TRADE_RETCODE_INVALID_FILL");
|
|
break;
|
|
case 10031:
|
|
return("TRADE_RETCODE_CONNECTION");
|
|
break;
|
|
case 10032:
|
|
return("TRADE_RETCODE_ONLY_REAL");
|
|
break;
|
|
case 10033:
|
|
return("TRADE_RETCODE_LIMIT_ORDERS");
|
|
break;
|
|
case 10034:
|
|
return("TRADE_RETCODE_LIMIT_VOLUME");
|
|
break;
|
|
case 10035:
|
|
return("TRADE_RETCODE_INVALID_ORDER");
|
|
break;
|
|
case 10036:
|
|
return("TRADE_RETCODE_POSITION_CLOSED");
|
|
break;
|
|
default:
|
|
return("TRADE_RETCODE_UNKNOWN="+IntegerToString(retcode));
|
|
break;
|
|
}
|
|
//---
|
|
}
|
|
//+------------------------------------------------------------------+
|