419 lines
39 KiB
MQL5
419 lines
39 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| ACM_Snipper.mq5 |
|
|
//| Anderson C Mourão |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#define MName "Expert Advisor MT5 ACM_Bot_Lettus123"
|
|
#define MVersion "25.09"
|
|
#define MBuild "2025-09-06 10:50 UTC(-3)"
|
|
#define MCopyright "Copyright \x00A9 2025, Anderson C Mourão, All rights reserved"
|
|
#define MProfile "https://forge.mql5.io/AndersonMourao"
|
|
|
|
#property strict
|
|
#property version MVersion
|
|
#property description MName
|
|
#property description "MetaTrader Expert Advisor (Build " MBuild ")"
|
|
#property copyright MCopyright
|
|
#property link MProfile
|
|
|
|
#property strict
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
|
|
#include <SymbolTradeMadeSimple.mqh>
|
|
#include <Trade/PositionInfo.mqh>
|
|
#include <Trade/Trade.mqh>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CTrade trade;
|
|
bool order_sent = false;
|
|
MqlDateTime stm, date_struct = {};
|
|
datetime tm = TimeTradeServer();
|
|
datetime now = tm;
|
|
datetime vTradingStartTime, vTradingEndTime;
|
|
double bid, ask, high, low, close, open, SL, TP, nTR, max_price;
|
|
// int ATRPeriod = 14;
|
|
// int ATRShift = 0; // Current bar
|
|
// int ATRHandle; // ATR indicator handle
|
|
int QtdAberta;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit() {
|
|
//--- set chart properties
|
|
ChartSetInteger(0, CHART_SHOW_TICKER, true); // Display a symbol ticker in the upper left corner. Setting CHART_SHOW_TICKER to 'false' also sets CHART_SHOW_OHLC to 'false' and disables OHLC
|
|
ChartSetInteger(0, CHART_SHOW_OHLC, true); // Display OHLC values in the upper left corner. Setting CHART_SHOW_OHLC to 'true' also sets CHART_SHOW_TICKER to 'true' and enables the ticker
|
|
ChartSetInteger(0, CHART_SHOW_BID_LINE, true); // Display Bid values as a horizontal line in a chart
|
|
ChartSetInteger(0, CHART_SHOW_ASK_LINE, true); // Display Ask values as a horizontal line in a chart
|
|
ChartSetInteger(0, CHART_SHOW_LAST_LINE, true); // Display Last values as a horizontal line in a chart
|
|
ChartSetInteger(0, CHART_SHOW_PERIOD_SEP, false); // Remove vertical separators between adjacent periods
|
|
ChartSetInteger(0, CHART_SHOW_GRID, false); // Remove grid in the chart
|
|
ChartSetInteger(0, CHART_SHOW_VOLUMES, false); // Remove volume in the chart
|
|
//--- convert current time to structure
|
|
TimeToStruct(tm, stm);
|
|
//--- escrevemos os valores de entrada nos campos correspondentes da estrutura
|
|
date_struct.year = stm.year;
|
|
date_struct.mon = stm.mon;
|
|
date_struct.day = stm.day;
|
|
//--- convertemos a data e a hora da estrutura em uma variável com o tipo datetime e
|
|
datetime dia_hoje = StructToTime(date_struct);
|
|
Print("Inicializando - ", MQL5InfoString(MQL5_PROGRAM_NAME), " - ", MVersion, " - ", MBuild);
|
|
PrintAccountInfo();
|
|
vTradingStartTime = dia_hoje;
|
|
// vTradingStartTime = dia_hoje + 9 * 3600;
|
|
vTradingEndTime = dia_hoje + 18 * 3600;
|
|
Print("Hora local = ", tm, " Hora abertura = ", vTradingStartTime, " Hora fechamento = ", vTradingEndTime);
|
|
Comment("Wait 5 minutes to startn each looping trading - ", now, "\n", MQL5InfoString(MQL5_PROGRAM_NAME), "\nVersion ", MVersion, " - ", MBuild);
|
|
EventSetTimer(10); // 5 minuto
|
|
|
|
bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
close = iClose(_Symbol, PERIOD_CURRENT, 0);
|
|
high = iHigh(_Symbol, PERIOD_CURRENT, 0);
|
|
low = iLow(_Symbol, PERIOD_CURRENT, 0);
|
|
open = iOpen(_Symbol, PERIOD_CURRENT, 0);
|
|
nTR = (((high - low) + MathAbs(close - open)) * 0.5);
|
|
|
|
//--- return INIT_SUCCEEDED if initialization completed successfully
|
|
return (INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason) {
|
|
Print("Finalizando - ", MQL5InfoString(MQL5_PROGRAM_NAME));
|
|
EventKillTimer();
|
|
PrintAccountInfo();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick() {
|
|
// Check if trading is allowed based on the defined start and end times
|
|
if(IsTradingBlocked()) {
|
|
// If not allowed, stop processing the rest of the OnTick function
|
|
Print("Fora do horário de mercado!");
|
|
CloseAllOpenOrders();
|
|
ExpertRemove();
|
|
}
|
|
|
|
bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
close = iClose(_Symbol, PERIOD_CURRENT, 0);
|
|
high = iHigh(_Symbol, PERIOD_CURRENT, 0);
|
|
low = iLow(_Symbol, PERIOD_CURRENT, 0);
|
|
open = iOpen(_Symbol, PERIOD_CURRENT, 0);
|
|
order_sent = PositionBuySellTicket() != 0;
|
|
nTR = (((high - low) + MathAbs(close - open)) * 0.5);
|
|
QtdAberta = SymbolOpenPositionsTotal(_Symbol);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer() {
|
|
if(order_sent && !IsTradingBlocked()) {
|
|
TrailingStop();
|
|
Comment("Looping trading in trailstop ", now, "\nQuantidade de ordens abertas: ", QtdAberta);
|
|
ChartRedraw();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CloseAllOpenOrders() {
|
|
Print("Fechando todas as ordens abertas!");
|
|
CloseAllPendingOrders();
|
|
trade.PositionClose(_Symbol);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
void CloseAllPendingOrders() {
|
|
int total_orders = OrdersTotal();
|
|
for(int i = total_orders - 1; i >= 0; i--) { // decrescente mesmo, vai ate 0
|
|
ulong ticket = OrderGetTicket(i);
|
|
trade.OrderDelete(ticket);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Script program start function |
|
|
//+------------------------------------------------------------------+
|
|
ulong PositionBuySellTicket() {
|
|
//--- in a loop by all account orders
|
|
ulong ticket = 0;
|
|
int total_orders = OrdersTotal();
|
|
for(int i = total_orders - 1; i >= 0; i--) {
|
|
//--- get the ticket of the next position by automatically selecting a position to access its properties
|
|
ticket = OrderGetTicket(i);
|
|
//--- if the position is not selected, then go to the next iteration of the loop
|
|
if(ticket == 0)
|
|
continue;
|
|
return (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE ? ticket : ticket);
|
|
}
|
|
return (0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Display real properties of the selected position in the journal |
|
|
//+------------------------------------------------------------------+
|
|
void PositionPropertiesDoublePrint(const uint header_width = 0) {
|
|
uint w = 0;
|
|
string header = "";
|
|
double value = 0;
|
|
|
|
//--- get the account currency, position symbol and the number of decimal places for the symbol
|
|
string currency = AccountInfoString(ACCOUNT_CURRENCY);
|
|
string symbol = PositionGetString(POSITION_SYMBOL);
|
|
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
|
|
|
//--- define the header text and the width of the header field
|
|
//--- if the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
|
|
header = "Volume:";
|
|
w = (header_width == 0 ? header.Length() + 1 : header_width);
|
|
//--- get and display the position volume with the specified header width in the journal
|
|
if(!PositionGetDouble(POSITION_VOLUME, value))
|
|
return;
|
|
PrintFormat("%-*s%-.2f", w, header, value);
|
|
|
|
//--- display the position price value in the journal
|
|
header = "Price open:";
|
|
w = (header_width == 0 ? header.Length() + 1 : header_width);
|
|
if(!PositionGetDouble(POSITION_PRICE_OPEN, value))
|
|
return;
|
|
PrintFormat("%-*s%-.*f", w, header, digits, value);
|
|
|
|
//--- display the StopLoss value in the journal
|
|
header = "StopLoss:";
|
|
w = (header_width == 0 ? header.Length() + 1 : header_width);
|
|
if(!PositionGetDouble(POSITION_SL, value))
|
|
return;
|
|
PrintFormat("%-*s%-.*f", w, header, digits, value);
|
|
|
|
//--- display the TakeProfit value in the journal
|
|
header = "TakeProfit:";
|
|
w = (header_width == 0 ? header.Length() + 1 : header_width);
|
|
if(!PositionGetDouble(POSITION_TP, value))
|
|
return;
|
|
PrintFormat("%-*s%-.*f", w, header, digits, value);
|
|
|
|
//--- display the 'Price current' value in the journal
|
|
header = "Price current:";
|
|
w = (header_width == 0 ? header.Length() + 1 : header_width);
|
|
if(!PositionGetDouble(POSITION_PRICE_CURRENT, value))
|
|
return;
|
|
PrintFormat("%-*s%-.*f", w, header, digits, value);
|
|
|
|
//--- display the accumulated swap value in the journal
|
|
header = "Swap:";
|
|
w = (header_width == 0 ? header.Length() + 1 : header_width);
|
|
if(!PositionGetDouble(POSITION_SWAP, value))
|
|
return;
|
|
PrintFormat("%-*s%-.2f", w, header, value);
|
|
|
|
//--- display the current profit value to the journal
|
|
header = "Profit:";
|
|
w = (header_width == 0 ? header.Length() + 1 : header_width);
|
|
if(!PositionGetDouble(POSITION_PROFIT, value))
|
|
return;
|
|
PrintFormat("%-*s%-.2f %s", w, header, value, currency);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void TrailingStop() {
|
|
ulong ticket = PositionBuySellTicket();
|
|
if(ticket > 0) {
|
|
double price_open = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
double price_current = PositionGetDouble(POSITION_PRICE_CURRENT);
|
|
double sl = PositionGetDouble(POSITION_SL);
|
|
double tp = PositionGetDouble(POSITION_TP);
|
|
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
|
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
|
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
double new_sl = 0.0;
|
|
// max_price = (AccountInfoDouble(ACCOUNT_BALANCE) * 0.01); // 1% do saldo
|
|
// PrintFormat("Ordem %I64u - Tipo %d - Preço Abertura: %.*f - Preço Atual: %.*f - SL Atual: %.*f", ticket, type, digits, price_open, digits, price_current, digits, sl);
|
|
//--- Trailing Stop para ordens BUY
|
|
// Move o stop apenas se o preço atual estiver acima do preço de abertura
|
|
if(type == POSITION_TYPE_BUY) {
|
|
if(price_current < max_price)
|
|
return;
|
|
max_price = price_current + nTR;
|
|
new_sl = price_current - nTR; // Move SL to 50 points below current price
|
|
if(new_sl > sl && new_sl > price_open) { // Ensure SL only moves up and is above open price
|
|
if(trade.PositionModify(_Symbol, new_sl, 0)) {
|
|
PrintFormat("Trailing Stop moved for BUY position. New SL: %.*f", digits, new_sl);
|
|
} else {
|
|
PrintFormat("Failed to move Trailing Stop for BUY position. Error: %d", GetLastError());
|
|
}
|
|
}
|
|
} else if(type == POSITION_TYPE_SELL) {
|
|
if(price_current > max_price)
|
|
return;
|
|
max_price = price_current - nTR;
|
|
new_sl = price_current + nTR; // Move SL to 10 points above current price
|
|
if(new_sl < sl && new_sl < price_open) { // Ensure SL only moves down and is below open price
|
|
if(trade.PositionModify(_Symbol, new_sl, 0)) {
|
|
PrintFormat("Trailing Stop moved for SELL position. New SL: %.*f", digits, new_sl);
|
|
} else {
|
|
PrintFormat("Failed to move Trailing Stop for SELL position. Error: %d", GetLastError());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| PrintAccountInfo() |
|
|
//+------------------------------------------------------------------+
|
|
void PrintAccountInfo() {
|
|
//--- trade server name
|
|
string server = AccountInfoString(ACCOUNT_SERVER);
|
|
//--- account number
|
|
int login = (int)AccountInfoInteger(ACCOUNT_LOGIN);
|
|
//--- long value output
|
|
long leverage = AccountInfoInteger(ACCOUNT_LEVERAGE);
|
|
printf("%s %d: leverage = 1:%I64d",
|
|
server, login, leverage);
|
|
//--- account currency
|
|
string currency = AccountInfoString(ACCOUNT_CURRENCY);
|
|
//--- double value output with 2 digits after the decimal point
|
|
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
|
|
printf("%s %d: account equity = %.2f %s",
|
|
server, login, equity, currency);
|
|
//--- double value output with mandatory output of the +/- sign
|
|
double profit = AccountInfoDouble(ACCOUNT_PROFIT);
|
|
printf("%s %d: current result for open positions = %+.2f %s",
|
|
server, login, profit, currency);
|
|
//--- double value output with variable number of digits after the decimal point
|
|
double point_value = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
|
string format_string = StringFormat("%%s: point value = %%.%df", _Digits);
|
|
printf(format_string, _Symbol, point_value);
|
|
//--- int value output
|
|
int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
|
|
printf("%s: current spread in points = %d ",
|
|
_Symbol, spread);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Helper function to check if trading is allowed. |
|
|
//+------------------------------------------------------------------+
|
|
bool IsTradingBlocked() {
|
|
// Check if it's within the defined start and end times
|
|
now = TimeTradeServer();
|
|
return (now < vTradingStartTime || now > vTradingEndTime);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
// void CheckATR(){
|
|
// double ATR[];
|
|
// ArrayResize(ATR,15);
|
|
// int hATR = iATR(_Symbol,_Period,15);
|
|
// //ArraySetAsSeries( ATR, true);
|
|
// CopyBuffer( hATR, 0, 0, 15, ATR ); //take number of average value
|
|
// // for ( int i=0 ; i<ArraySize(ATR) ; i++ ){
|
|
// // Print("the ATR " + i + " is " + ATR[i]);
|
|
// // }
|
|
// }
|
|
|
|
// double getIndicator(int v)
|
|
// {
|
|
// int handle = iCustom(curSymbol,Indicator_Period,"Market\\Entry Points Pro for MT5");
|
|
// //,1000,true);
|
|
// // ,false,false,500,false,"09:00","23:59",false
|
|
// //,30,255,3329330,14772545,9,true,true,true,"alert2.wav"
|
|
// double myArray[];
|
|
// int copy=CopyBuffer(handle,v,0,1,myArray);
|
|
// return (double)myArray[0];
|
|
// }
|
|
|
|
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
|
|
Print("Hora: ", now, " Key pressed: ", (char)lparam, " order_sent : ", order_sent, "\nPreço Bid: ", bid, " Preço Ask: ", ask, " Preço Close: ", close, " Preço Open: ", open);
|
|
|
|
if(id == CHARTEVENT_KEYDOWN) {
|
|
if(!order_sent) {
|
|
|
|
if((char)lparam == 'c' || (char)lparam == 'C') {
|
|
// Comprar
|
|
SL = close - nTR;
|
|
TP = close + nTR * 2;
|
|
max_price = close + nTR; // 50% do take profit
|
|
PrintFormat("Preço do inicio Trailstop: %.*f", _Digits, max_price);
|
|
order_sent = trade.BuyLimit(1.0, bid, _Symbol, SL, TP, ORDER_TIME_DAY, 0, "Manual Buy Limit at " + (string)bid + " SL: " + (string)SL + " TP: " + (string)TP);
|
|
if(!order_sent)
|
|
Print("Erro ao enviar ordem de compra. Código do erro: ", GetLastError());
|
|
}
|
|
if((char)lparam == 'v' || (char)lparam == 'V') {
|
|
// Vender
|
|
SL = close + nTR;
|
|
TP = close - nTR * 2;
|
|
max_price = close - nTR; // 50% do take profit
|
|
PrintFormat("Preço do inicio Trailstop: %.*f", _Digits, max_price);
|
|
order_sent = trade.SellLimit(1.0, ask, _Symbol, SL, TP, ORDER_TIME_DAY, 0, "Manual Sell Limit at " + (string)ask + " SL: " + (string)SL + " TP: " + (string)TP);
|
|
if(!order_sent)
|
|
Print("Erro ao enviar ordem de venda. Código do erro: ", GetLastError());
|
|
}
|
|
}
|
|
|
|
if((char)lparam == 'p' || (char)lparam == 'P') {
|
|
CloseAllPendingOrders();
|
|
}
|
|
|
|
if((char)lparam == 'r' || (char)lparam == 'R') {
|
|
CloseAllOpenOrders();
|
|
}
|
|
|
|
// Fechar todas as ordens abertas e remover o EA do gráfico
|
|
if((char)lparam == 'x' || (char)lparam == 'X') {
|
|
CloseAllOpenOrders();
|
|
ExpertRemove();
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Robo Lettus123! |
|
|
//+------------------------------------------------------------------+
|
|
void AbrePosicao() {
|
|
//--- Perform trading actions
|
|
// CloseAllOpenOrders();
|
|
order_sent = PositionSelect(_Symbol);
|
|
double ATRBuffer[];
|
|
int ATR = iATR(_Symbol, PERIOD_CURRENT, 14);
|
|
if(CopyBuffer(ATR, 0, 0, 1, ATRBuffer) <= 0) {
|
|
Print("Failed to copy data from the ATR indicator. Error code: ", GetLastError());
|
|
return;
|
|
}
|
|
double nATR = NormalizeDouble(ATRBuffer[0], _Digits);
|
|
|
|
Comment("in looping trading - ", now, " -> ", close, " -> ", nATR);
|
|
|
|
if(open < close) {
|
|
Print("Comprando.. ", _Symbol, " - ", now, " - bid: ", bid);
|
|
double stop = bid - nATR;
|
|
double take = bid + nATR;
|
|
order_sent = trade.BuyLimit(1.0, bid, _Symbol, stop, take, ORDER_TIME_DAY, 0, (string)close + " -> " + (string)nATR);
|
|
if(!order_sent)
|
|
Print("Erro ao enviar ordem de compra. Código do erro: ", GetLastError());
|
|
} else if(open > close) {
|
|
|
|
Print("Vendendo.. ", _Symbol, " - ", now, " - ask: ", ask);
|
|
double stop = ask + nATR;
|
|
double take = ask - nATR;
|
|
order_sent = trade.SellLimit(1.0, ask, _Symbol, stop, take, ORDER_TIME_DAY, 0, (string)close + " <- " + (string)nATR);
|
|
if(!order_sent)
|
|
Print("Erro ao enviar ordem de venda. Código do erro: ", GetLastError());
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|