MQL5, không cần cảm ơn
//+------------------------------------------------------------------+
//| OneClick_DualPending.mq5 |
//| Place BuyStop + SellStop simultaneously by one button |
//+------------------------------------------------------------------+
#property strict
#property version "1.00"
#include <Trade/Trade.mqh>
CTrade trade;
//==================== USER SETTINGS ====================//
input long InpMagicNumber = 20260210;
input bool InpPreventDup = true; // tránh đặt trùng nếu đã có pending của EA
input int InpSlippagePts = 20; // slippage (points)
input string InpOrderComment = "DualPending";
//==================== UI DEFAULT VALUES ====================//
input double DefaultDistancePips = 20; // khoảng cách pending (pip)
input double DefaultLot = 0.01;
input double DefaultTP_Pips = 30;
input double DefaultSL_Pips = 30;
//==================== UI OBJECT NAMES ====================//
string OBJ_BTN = "DP_BTN_PLACE";
string OBJ_ED1 = "DP_ED_DIST";
string OBJ_ED2 = "DP_ED_LOT";
string OBJ_ED3 = "DP_ED_TP";
string OBJ_ED4 = "DP_ED_SL";
string OBJ_LB1 = "DP_LB_DIST";
string OBJ_LB2 = "DP_LB_LOT";
string OBJ_LB3 = "DP_LB_TP";
string OBJ_LB4 = "DP_LB_SL";
//-------------------- pip conversion --------------------//
double PipValue()
{
// 5-digit/3-digit: 1 pip = 10 points
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(digits == 3 || digits == 5) return point * 10.0;
return point;
}
double StrToD(const string s, double fallback)
{
string t = s;
StringTrimLeft(t); StringTrimRight(t);
if(t == "" ) return fallback;
return (double)StringToDouble(t);
}
//-------------------- check existing pending --------------------//
bool HasPendingOfThisEA()
{
int total = OrdersTotal();
for(int i = 0; i < total; i++)
{
ulong ticket = OrderGetTicket(i);
if(ticket == 0) continue;
if(!OrderSelect(ticket)) continue;
if(OrderGetString(ORDER_SYMBOL) != _Symbol) continue;
if((long)OrderGetInteger(ORDER_MAGIC) != InpMagicNumber) continue;
ENUM_ORDER_TYPE type = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE);
if(type == ORDER_TYPE_BUY_STOP || type == ORDER_TYPE_SELL_STOP)
return true;
}
return false;
}
//-------------------- UI helpers --------------------//
void CreateLabel(const string name, int x, int y, const string text)
{
if(ObjectFind(0, name) >= 0) return;
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetString (0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
}
void CreateEdit(const string name, int x, int y, const string text, int w=90)
{
if(ObjectFind(0, name) >= 0) return;
ObjectCreate(0, name, OBJ_EDIT, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, name, OBJPROP_XSIZE, w);
ObjectSetInteger(0, name, OBJPROP_YSIZE, 18);
ObjectSetString (0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
}
void CreateButton(const string name, int x, int y, const string text, int w=120, int h=24)
{
if(ObjectFind(0, name) >= 0) return;
ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, name, OBJPROP_XSIZE, w);
ObjectSetInteger(0, name, OBJPROP_YSIZE, h);
ObjectSetString (0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
}
void BuildUI()
{
int x0 = 10, y0 = 20, dy = 22;
CreateLabel(OBJ_LB1, x0, y0 + dy*0, "Distance (
pips):");
CreateEdit (OBJ_ED1, x0+110, y0 + dy*0, DoubleToString(DefaultDistancePips, 1));
CreateLabel(OBJ_LB2, x0, y0 + dy*1, "Lot:");
CreateEdit (OBJ_ED2, x0+110, y0 + dy*1, DoubleToString(DefaultLot, 2));
CreateLabel(OBJ_LB3, x0, y0 + dy*2, "TP (
pips):");
CreateEdit (OBJ_ED3, x0+110, y0 + dy*2, DoubleToString(DefaultTP_Pips, 1));
CreateLabel(OBJ_LB4, x0, y0 + dy*3, "SL (
pips):");
CreateEdit (OBJ_ED4, x0+110, y0 + dy*3, DoubleToString(DefaultSL_Pips, 1));
CreateButton(OBJ_BTN, x0, y0 + dy*4 + 6, "PLACE BOTH");
}
//-------------------- place orders --------------------//
void PlaceBoth()
{
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
{
Print("Trade not allowed in terminal.");
return;
}
if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
{
Print("Trade not allowed for EA (check AutoTrading).");
return;
}
// read values from edits
string sDist = ObjectGetString(0, OBJ_ED1, OBJPROP_TEXT);
string sLot = ObjectGetString(0, OBJ_ED2, OBJPROP_TEXT);
string sTP = ObjectGetString(0, OBJ_ED3, OBJPROP_TEXT);
string sSL = ObjectGetString(0, OBJ_ED4, OBJPROP_TEXT);
double dist_pips = StrToD(sDist, DefaultDistancePips);
double lot = StrToD(sLot, DefaultLot);
double tp_pips = StrToD(sTP, DefaultTP_Pips);
double sl_pips = StrToD(sSL, DefaultSL_Pips);
if(dist_pips <= 0 || lot <= 0)
{
Print("Invalid Distance/Lot.");
return;
}
if(InpPreventDup && HasPendingOfThisEA())
{
Print("Pending orders already exist for this EA (PreventDup=ON).");
return;
}
// pip step
double pip = PipValue();
// prices
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double buy_price = NormalizeDouble(ask + dist_pips * pip, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
double sell_price = NormalizeDouble(bid - dist_pips * pip, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
// tp/sl
double buy_tp = 0, buy_sl = 0, sell_tp = 0, sell_sl = 0;
if(tp_pips > 0)
{
buy_tp = NormalizeDouble(buy_price + tp_pips * pip, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
sell_tp = NormalizeDouble(sell_price - tp_pips * pip, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
}
if(sl_pips > 0)
{
buy_sl = NormalizeDouble(buy_price - sl_pips * pip, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
sell_sl = NormalizeDouble(sell_price + sl_pips * pip, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
}
// trade settings
trade.SetExpertMagicNumber(InpMagicNumber);
trade.SetDeviationInPoints(InpSlippagePts);
bool ok1=false, ok2=false;
// Place Buy Stop
ok1 = trade.BuyStop(lot, buy_price, _Symbol, buy_sl, buy_tp, ORDER_TIME_GTC, 0, InpOrderComment);
if(!ok1)
Print("BuyStop failed. Retcode=", trade.ResultRetcode(), " ", trade.ResultRetcodeDescription());
// Place Sell Stop
ok2 = trade.SellStop(lot, sell_price, _Symbol, sell_sl, sell_tp, ORDER_TIME_GTC, 0, InpOrderComment);
if(!ok2)
Print("SellStop failed. Retcode=", trade.ResultRetcode(), " ", trade.ResultRetcodeDescription());
if(ok1 && ok2)
Print("Placed BOTH pending orders successfully. Dist=",dist_pips,"
pips Lot=",lot," TP=",tp_pips," SL=",sl_pips);
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
BuildUI();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
string arr[] = {OBJ_BTN,OBJ_ED1,OBJ_ED2,OBJ_ED3,OBJ_ED4,OBJ_LB1,OBJ_LB2,OBJ_LB3,OBJ_LB4};
for(int i=0;i<ArraySize(arr);i++)
if(ObjectFind(0, arr
) >= 0) ObjectDelete(0, arr);
}
//+------------------------------------------------------------------+
//| Chart event function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(id == CHARTEVENT_OBJECT_CLICK)
{
if(sparam == OBJ_BTN)
PlaceBoth();
}
}