mathmarketmodels/ExpertMM1_v3.mq5

610 lines
No EOL
46 KiB
MQL5

//+------------------------------------------------------------------+
//| ExpertMM1.mq5 |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property description "Exemplo de EA"
#include <Trade\PositionInfo.mqh> //Instatiate Library for Positions Information
#include <Trade\Trade.mqh>
#include <Trade\AccountInfo.mqh>
input double lots=0.01; // volume em lotes
input int slippage=10; // derrapagem admissível
input bool revers=false; // invertemos o sinal?
input ulong EXPERT_MAGIC=0; // MagicNumber do EA
double trade_lot;
double lastAskHit;
CTrade m_trade; // Trades Info and Executions library
COrderInfo m_order; //Library for Orders information
CPositionInfo m_position; // Library for all position features and information
CAccountInfo m_account;
double OpenVolume=0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- definimos o volume correto
double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
trade_lot=lots>min_lot? lots:min_lot;
//--- criamos o identificador do indicador ATR
//--- inicialização bem-sucedida do EA
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- relatamos o código de desligamento do EA
Print(__FILE__,": Código de motivo da desinicialização = ",reason);
//--- destroy timer
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
double dailyHigh = iHigh(Symbol(), PERIOD_M15, 1); // Get the daily high
double dailyLow = iLow(Symbol(), PERIOD_M15, 1); // Get the daily low
double bidPrice = SymbolInfoDouble(Symbol(), SYMBOL_BID); // Get the current Bid price
double askPrice = SymbolInfoDouble(Symbol(), SYMBOL_ASK); // Get the current Ask price
if(m_account.MarginLevel() < 200)
CloseAllPositions();
if(GetAccountOpenPositions(Symbol())>0.20 || GetAccountOpenPositions(Symbol())<-0.20 )
CloseAllPositions();
if(isNewBar())
{
// Check if there are no open positions
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = Symbol();
request.volume = 0.01; // Fixed lot size 0.01
request.deviation = 20; // Increased slippage tolerance
request.magic = EXPERT_MAGIC; // Use user-defined Magic Number
request.comment = "Daily High/Low EA";
// Set order filling mode dynamically
ENUM_ORDER_TYPE_FILLING fillingMode;
if (SymbolInfoInteger(Symbol(), SYMBOL_FILLING_MODE) & SYMBOL_FILLING_IOC)
fillingMode = ORDER_FILLING_IOC;
else
fillingMode = ORDER_FILLING_RETURN;
request.type_filling = fillingMode;
request.type_time = ORDER_TIME_GTC; // Good till canceled
// ✅ Buy condition: Ask price reaches near the daily high
if (askPrice >= dailyHigh & GetAccountOpenPositions(Symbol())<=0)
{
//if(GetAccountOpenPositions(Symbol())>0)
// CloseAllPositions();
request.type = ORDER_TYPE_SELL;
request.price = askPrice; // Buying at Ask price
request.sl = askPrice + 100 * Point();
Print("Placing BUY order at Ask: ", askPrice);
// Send the order
if (!OrderSend(request, result))
Print("Trade execution error: ", result.comment);
else
Print("Order placed: ", result.price, " | Magic Number: ", EXPERT_MAGIC);
}
// ✅ Sell condition: Bid price reaches near the daily low
else if (bidPrice <= dailyLow & GetAccountOpenPositions(Symbol())>=0)
{
///if(GetAccountOpenPositions(Symbol())<0)
//CloseAllPositions();
request.type = ORDER_TYPE_BUY;
request.price = bidPrice; // Selling at Bid price;
request.sl = request.price - 100 * Point();
Print("Placing SELL order at Bid: ", bidPrice);
// Send the order
if (!OrderSend(request, result))
Print("Trade execution error: ", result.comment);
else
Print("Order placed: ", result.price, " | Magic Number: ", EXPERT_MAGIC);
}
else
return; // No trade condition met
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Returns true if a new bar has appeared for a symbol/period pair |
//+------------------------------------------------------------------+
bool isNewBar()
{
//--- memorize the time of opening of the last bar in the static variable
static datetime last_time=0;
//--- current time
datetime lastbar_time=SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE);
//--- if it is the first call of the function
if(last_time==0)
{
//--- set the time and exit
last_time=lastbar_time;
return(false);
}
//--- if the time differs
if(last_time!=lastbar_time)
{
//--- memorize the time and return true
last_time=lastbar_time;
return(true);
}
//--- if we passed to this line, then the bar is not new; return false
return(false);
}
//+------------------------------------------------------------------+
//| Returns type of a pending order in a random way |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetRandomType()
{
int t=MathRand()%2;
//--- 0<=t<4
switch(t)
{
case(0):return(ORDER_TYPE_BUY_LIMIT);
case(1):return(ORDER_TYPE_SELL_LIMIT);
}
//--- incorrect value
return(WRONG_VALUE);
}
//+------------------------------------------------------------------+
//| Deletes all pending orders with specified ORDER_MAGIC |
//+------------------------------------------------------------------+
void DeleteAllOrdersByMagic(long const magic_number)
{
ulong order_ticket;
//--- go through all pending orders
for(int i=OrdersTotal()-1;i>=0;i--)
if((order_ticket=OrderGetTicket(i))>0)
//--- order with appropriate ORDER_MAGIC
if(magic_number==OrderGetInteger(ORDER_MAGIC))
{
MqlTradeResult result={};
MqlTradeRequest request={};
request.order=order_ticket;
request.action=TRADE_ACTION_REMOVE;
OrderSend(request,result);
//--- write the server reply to log
Print(__FUNCTION__,": ",result.comment," reply code ",result.retcode);
}
//---
}
int GetOrdersTotalByMagic(long const magic_number)
{
ulong order_ticket;
int total=0;
//--- go through all pending orders
for(int i=0;i<OrdersTotal();i++)
if((order_ticket=OrderGetTicket(i))>0)
if(magic_number==OrderGetInteger(ORDER_MAGIC)) total++;
//---
return(total);
}
//+------------------------------------------------------------------+
//| Buy at a market price with a specified volume |
//+------------------------------------------------------------------+
bool Buy(double volume,ulong deviation=10,ulong magicnumber=0)
{
//--- buy at a market price
return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
}
//+------------------------------------------------------------------+
//| Sell at a market price with a specified volume |
//+------------------------------------------------------------------+
bool Sell(double volume,ulong deviation=10,ulong magicnumber=0)
{
//--- sell at a market price
return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
}
//+------------------------------------------------------------------+
//| Sets a pending order in a random way |
//+------------------------------------------------------------------+
uint SendRandomPendingOrder(long const magic_number)
{
//--- prepare a request
MqlTradeRequest request={};
request.action=TRADE_ACTION_PENDING; // setting a pending order
request.magic=magic_number; // ORDER_MAGIC
request.symbol=_Symbol; // symbol
request.volume=0.01; // volume in 0.01 lots
request.sl=0;
request.tp=0; // Take Profit is not specified
//--- form the order type
request.type=GetRandomType(); // order type
//request.type=ORDER_TYPE_BUY_LIMIT;
//--- form the price for the pending order
request.price=GetRandomPrice(request.type); // open price
if(request.type==ORDER_TYPE_BUY_LIMIT)
{
request.tp=iHigh(Symbol(),PERIOD_D1,0);
request.sl=iLow(Symbol(),PERIOD_D1,0);
}
else
if(request.type==ORDER_TYPE_SELL_LIMIT) // ORDER_TYPE_SELL_LIMIT or ORDER_TYPE_BUY_STOP
{
request.tp=iLow(Symbol(),PERIOD_D1,0);
request.sl=iHigh(Symbol(),PERIOD_D1,0);
}
else
return false;
//--- send a trade request
MqlTradeResult result={};
OrderSend(request,result);
//--- write the server reply to log
Print(__FUNCTION__,":",result.comment);
if(result.retcode==10016) Print(result.bid,result.ask,result.price);
//--- return code of the trade server reply
return result.retcode;
}
//+------------------------------------------------------------------+
//| Prepare and send a trade request |
//+------------------------------------------------------------------+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
{
//--- declaring and initializing structures
MqlTradeRequest request={};
MqlTradeResult result={};
double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
if(type==ORDER_TYPE_BUY)
price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
if(type==ORDER_TYPE_BUY_LIMIT)
price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
if(type==ORDER_TYPE_SELL)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
if(type==ORDER_TYPE_SELL_LIMIT)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- request parameters
request.action =TRADE_ACTION_DEAL; // trading operation type
request.position =pos_ticket; // position ticket if closing
request.symbol =Symbol(); // symbol
request.volume =volume; // volume
request.type =type; // order type
request.price =price; // trade price
request.deviation=slip; // allowable deviation from the price
request.magic =magicnumber; // order MagicNumber
//--- send a request
if(!OrderSend(request,result))
{
//--- display data on failure
PrintFormat("OrderSend %s %s %.2f at %.5f error %d",
request.symbol,EnumToString(type),volume,request.price,GetLastError());
return (false);
}
//--- inform of a successful operation
PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order);
return (true);
}
//+------------------------------------------------------------------+
//| Returns price in a random way |
//+------------------------------------------------------------------+
double GetRandomPrice(ENUM_ORDER_TYPE type)
{
int t=(int)type;
//--- stop levels for the symbol
int distance=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
if(distance<=0)
distance=150;
else
distance+=50;
//--- receive data of the last tick
MqlTick last_tick={};
SymbolInfoTick(_Symbol,last_tick);
//--- calculate price according to the type
double price;
if(t==ORDER_TYPE_BUY_LIMIT ) // ORDER_TYPE_BUY_LIMIT or ORDER_TYPE_SELL_STOP
{
price=last_tick.bid; // depart from price Bid
price=price-distance*_Point;
}
else
if(t==ORDER_TYPE_SELL_LIMIT ) // ORDER_TYPE_SELL_LIMIT or ORDER_TYPE_BUY_STOP
{
price=last_tick.ask; // depart from price Ask
price=price+distance*_Point;
}
//---
return(price);
}
//+------------------------------------------------------------------+
//| Close all positions |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i=PositionsTotal()-1;i>=0;i--) // returns the number of current positions
if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
m_trade.PositionClose(m_position.Ticket()); // close a position by the specified symbol
}
//+------------------------------------------------------------------+
//| Is position exists |
//+------------------------------------------------------------------+
bool IsPositionExists(void)
{
for(int i=PositionsTotal()-1;i>=0;i--)
if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
return(true);
//---
return(false);
}
bool CheckMoneyForTrade(string symb,double lot,ENUM_ORDER_TYPE type)
{
//--- Getting the opening price
MqlTick mqltick;
SymbolInfoTick(symb,mqltick);
double price=mqltick.ask;
if(type==ORDER_TYPE_SELL)
price=mqltick.bid;
//--- values of the required and free margin
double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
//--- call of the checking function
if(!OrderCalcMargin(type,symb,lot,price,margin))
{
//--- something went wrong, report and return false
Print("Error in ",__FUNCTION__," code=",GetLastError());
return(false);
}
//--- if there are insufficient funds to perform the operation
if(margin>free_margin)
{
//--- report the error and return false
Print("Not enough money for ",EnumToString(type)," ",lot," ",symb," Error code=",GetLastError());
return(false);
}
//--- checking successful
return(true);
}
//+------------------------------------------------------------------+
//| Check the correctness of the order volume |
//+------------------------------------------------------------------+
bool CheckVolumeValue(double volume,string &description)
{
//--- minimal allowed volume for trade operations
double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
if(volume<min_volume)
{
description=StringFormat("Volume is less than the minimal allowed SYMBOL_VOLUME_MIN=%.2f",min_volume);
return(false);
}
//--- maximal allowed volume of trade operations
double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
if(volume>max_volume)
{
description=StringFormat("Volume is greater than the maximal allowed SYMBOL_VOLUME_MAX=%.2f",max_volume);
return(false);
}
//--- get minimal step of volume changing
double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);
int ratio=(int)MathRound(volume/volume_step);
if(MathAbs(ratio*volume_step-volume)>0.0000001)
{
description=StringFormat("Volume is not a multiple of the minimal step SYMBOL_VOLUME_STEP=%.2f, the closest correct volume is %.2f",
volume_step,ratio*volume_step);
return(false);
}
description="Correct volume value";
return(true);
}
//+------------------------------------------------------------------+
//| Check if another order can be placed |
//+------------------------------------------------------------------+
bool IsNewOrderAllowed()
{
//--- get the number of pending orders allowed on the account
int max_allowed_orders=(int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS);
//--- if there is no limitation, return true; you can send an order
if(max_allowed_orders==0) return(true);
//--- if we passed to this line, then there is a limitation; find out how many orders are already placed
int orders=OrdersTotal();
//--- return the result of comparing
return(orders<max_allowed_orders);
}
//+------------------------------------------------------------------+
//| Return the size of position on the specified symbol |
//+------------------------------------------------------------------+
double PositionVolume(string symbol)
{
//--- try to select position by a symbol
bool selected=PositionSelect(symbol);
//--- there is a position
if(selected)
//--- return volume of the position
return(PositionGetDouble(POSITION_VOLUME));
else
{
//--- report a failure to select position
Print(__FUNCTION__," Failed to perform PositionSelect() for symbol ",
symbol," Error ",GetLastError());
return(-1);
}
}
//+------------------------------------------------------------------+
//| returns the volume of current pending order by a symbol |
//+------------------------------------------------------------------+
double PendingsVolume(string symbol)
{
double volume_on_symbol=0;
ulong ticket;
//--- get the number of all currently placed orders by all symbols
int all_orders=OrdersTotal();
//--- get over all orders in the loop
for(int i=0;i<all_orders;i++)
{
//--- get the ticket of an order by its position in the list
ticket=OrderGetTicket(i);
//--- if our symbol is specified in the order, add the volume of this order
if(symbol==OrderGetString(ORDER_SYMBOL))
volume_on_symbol+=OrderGetDouble(ORDER_VOLUME_INITIAL);
}
//--- return the total volume of currently placed pending orders for a specified symbol
return(volume_on_symbol);
}
//+------------------------------------------------------------------+
//| Return the maximum allowed volume for an order on the symbol |
//+------------------------------------------------------------------+
double NewOrderAllowedVolume(string symbol)
{
double allowed_volume=0;
//--- get the limitation on the maximal volume of an order
double symbol_max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
//--- get the limitation on the volume by a symbol
double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT);
//--- get the volume of the open position by a symbol
double opened_volume=PositionVolume(symbol);
if(opened_volume>=0)
{
//--- if we have exhausted the volume
if(max_volume-opened_volume<=0)
return(0);
//--- volume of the open position doesn't exceed max_volume
double orders_volume_on_symbol=PendingsVolume(symbol);
allowed_volume=max_volume-opened_volume-orders_volume_on_symbol;
if(allowed_volume>symbol_max_volume) allowed_volume=symbol_max_volume;
}
return(allowed_volume);
}
//+------------------------------------------------------------------+
//| Return the volume open in symbol |
//+------------------------------------------------------------------+
double GetAccountOpenPositions(string symbol)
{
double totalVolume=0;
// Loop through all open positions and print their volume
int totalPositions = PositionsTotal(); // Get the total number of open positions
for (int i = 0; i < totalPositions; i++)
{
if (m_position.SelectByIndex(i)) // Select the position by index
{
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
totalVolume += PositionGetDouble(POSITION_VOLUME); // Get the volume of the position
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
totalVolume -= PositionGetDouble(POSITION_VOLUME); // Get the volume of the position
}
}
return totalVolume;
}