存成 MQL5/Experts/Lesson11RawOrder.mq5。僅限模擬。它手動組出請求、依序嘗試 FOK 再 IOC 再 RETURN,並印出完整結果——也就是 CTrade 藏起來的那套邏輯。
//+------------------------------------------------------------------+
//| Lesson 11 - Raw OrderSend, filling modes, retcodes |
//| WARNING: sends real market orders. Use a DEMO account. |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version "1.00"
#property strict
input double Lots = 0.10;
input int StopPoints = 200;
input int Deviation = 10;
input ulong MagicNumber = 11111111;
datetime lastBarTime = 0;
int OnInit()
{
Print("Filling mode supported by ", _Symbol, ": ",
EnumToString((ENUM_ORDER_TYPE_FILLING)SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE)));
return(INIT_SUCCEEDED);
}
void OnTick()
{
datetime t = iTime(_Symbol, _Period, 0);
if(t == lastBarTime) return;
lastBarTime = t;
if(PositionSelect(_Symbol))
{
Print("Position already open - skipping.");
return;
}
OpenBuy(Lots, StopPoints);
}
//+------------------------------------------------------------------+
//| Market buy built by hand, with a filling-mode fallback chain |
//+------------------------------------------------------------------+
void OpenBuy(const double lots, const double stopPoints)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = NormalizeDouble(ask - stopPoints * _Point, _Digits);
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.volume = NormalizeDouble(lots, 2);
req.type = ORDER_TYPE_BUY;
req.price = ask;
req.sl = sl;
req.deviation = Deviation;
req.magic = MagicNumber;
req.comment = "lesson11";
// Ask the symbol first; fall back through the rest if the server refuses.
long supported = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
ENUM_ORDER_TYPE_FILLING modes[3];
if((supported & SYMBOL_FILLING_FOK) != 0)
{ modes[0] = ORDER_FILLING_FOK; modes[1] = ORDER_FILLING_IOC; modes[2] = ORDER_FILLING_RETURN; }
else if((supported & SYMBOL_FILLING_IOC) != 0)
{ modes[0] = ORDER_FILLING_IOC; modes[1] = ORDER_FILLING_RETURN; modes[2] = ORDER_FILLING_FOK; }
else
{ modes[0] = ORDER_FILLING_RETURN; modes[1] = ORDER_FILLING_FOK; modes[2] = ORDER_FILLING_IOC; }
for(int i = 0; i < 3; i++)
{
req.type_filling = modes[i];
ResetLastError();
if(!OrderSend(req, res))
{
Print("OrderSend failed with ", EnumToString(modes[i]),
". GetLastError=", GetLastError());
continue;
}
Print("Sent with ", EnumToString(modes[i]),
" -> retcode=", res.retcode,
" deal=", res.deal,
" volume=", DoubleToString(res.volume, 2),
" price=", DoubleToString(res.price, _Digits));
if(res.retcode == TRADE_RETCODE_DONE || res.retcode == TRADE_RETCODE_PLACED)
{
Print("SUCCESS: order accepted.");
return;
}
// Retcode-specific hints - do not blindly retry these.
if(res.retcode == TRADE_RETCODE_INVALID_STOPS)
{
Print("Invalid stops: your SL/TP is too close. Broker minimum is ",
SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL), " points.");
return;
}
if(res.retcode == TRADE_RETCODE_NO_MONEY)
{
Print("Not enough margin. Free margin: ",
DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN_FREE), 2));
return;
}
Print("Rejected with retcode ", res.retcode, " - check the retcode table.");
return;
}
}