MQL5 CTrade Class Guide: Buy, PositionClose & PositionModify Signatures
Master the MQL5 CTrade standard library class. Inspect exact function signatures for CTrade::Buy, PositionClose, and PositionModify, with parameter tables, return code checks, and educational EA order-execution examples.
What this MQL5 guide covers
CTrade simplifies MQL5 order routing by wrapping low-level MqlTradeRequest and OrderSend into clean object-oriented method calls.
CTrade::Buy accepts volume, symbol, execution price, stop-loss, take-profit, and order comments with sensible defaults.
PositionClose supports both symbol-based closing on netting accounts and ticket-based closing on hedging accounts.
Always inspect trade.ResultRetcode() and trade.ResultRetcodeDescription() to detect requotes, invalid stops, and volume limits.
CTrade::Buy Method Signatures and Parameter Specifications
The CTrade class resides in the standard library header <Trade\Trade.mqh>. Buy requests a market long position. Pending orders use separate methods such as BuyLimit, BuyStop or OrderOpen.
The primary market buy signature requires volume as the first parameter. If symbol is omitted or set to NULL, CTrade automatically uses the current chart symbol (_Symbol). When execution price is 0.0, the current Ask price is retrieved automatically by the terminal.
| Parameter | Type | Default | Description |
|---|---|---|---|
| volume | double | Required | Trade volume in lots (must conform to symbol lot step) |
| symbol | const string | NULL | Symbol name. NULL selects the chart symbol _Symbol |
| price | double | 0.0 | Open price. 0.0 resolves to current SymbolInfoDouble(symbol, SYMBOL_ASK) |
| sl | double | 0.0 | Stop loss price level (must satisfy symbol stop level distance) |
| tp | double | 0.0 | Take profit price level (must satisfy symbol stop level distance) |
| comment | const string | "" | Custom string comment attached to the resulting deal and order |
PositionClose and PositionModify Signatures
Both symbol and ticket overloads are available. Account mode changes the position selected by a symbol: netting has one aggregated position per instrument, while hedging can have several.
PositionClose(symbol) targets the symbol position in netting, and the lowest-ticket position for that symbol in hedging. PositionClose(ticket) targets the specified ticket. Check ownership before either request.
CTrade::PositionModify updates the stop-loss and take-profit of an active position. On hedging accounts, specify the position ticket as the first parameter; on netting accounts, passing the symbol string is supported.
| Method | Parameters | Return Type | Account Mode |
|---|---|---|---|
| PositionClose(symbol, deviation) | const string symbol, ulong deviation=ULONG_MAX | bool | Netting; lowest ticket in hedging |
| PositionClose(ticket, deviation) | ulong ticket, ulong deviation=ULONG_MAX | bool | Either mode, specified ticket |
| PositionModify(ticket, sl, tp) | ulong ticket, double sl, double tp | bool | Either mode, specified ticket |
| PositionModify(symbol, sl, tp) | const string symbol, double sl, double tp | bool | Netting; lowest ticket in hedging |
Return Code Verification and Execution Diagnostics
A true return from CTrade::Buy means the structures passed checks, not proof of a completed trade. Inspect ResultRetcode, ResultDeal and the resulting account state.
TRADE_RETCODE_DONE (10009) reports request completion; TRADE_RETCODE_PLACED (10008) reports an order placed, not a full fill. DONE_PARTIAL (10010) requires handling remaining volume. Codes such as 10016 (Invalid stops), 10014 (Invalid volume), and 10004 (Requote) require programmatic recovery.
- ResultRetcode(): Returns uint numeric response code from the trading server.
- ResultRetcodeDescription(): Human-readable text describing the execution outcome.
- ResultOrder(): Ticket number of the newly placed order.
- ResultDeal(): Ticket number of the completed deal recorded in trade history.
Implementation details & mechanics
Core implementation pattern
Configure CTrade magic, deviation and symbol filling in OnInit. The demonstration is disabled by default; enabling AllowDemoOrder on a demo account permits one buy attempt per EA initialization while the account has no positions. It is a method-call example, not an entry strategy. The SL/TP inputs are points, not pips.
Error handling & safety rules
ModifyPositionSLTP and CloseSpecificPosition are illustrative helpers, not automatically triggered exits. They select the ticket, verify symbol/magic ownership and check the server result. The sample does not implement full tick-grid, volume-step, margin, stop/freeze-level or partial-fill recovery logic; test those for the broker and use account-state reconciliation before retrying.
MQL5 Code Implementation
//+------------------------------------------------------------------+
//| CTradeClassGuideEA.mq5 |
//| Copyright 2026, Pineify Guides Series |
//| https://pineify.app |
//+------------------------------------------------------------------+
#property copyright "Pineify Guides Series"
#property link "https://pineify.app/mql5/ctrade-class-guide"
#property version "1.00"
#property strict
// Include standard trade library
#include <Trade\Trade.mqh>
//--- Input parameters
input group "--- Order Settings ---"
input bool AllowDemoOrder=false; // Explicit demo-only, one-attempt method example
input double InpLotSize = 0.10; // Lot volume
input int InpStopLossPoints = 250; // Stop Loss in points
input int InpTakeProfitPoints= 500; // Take Profit in points
input ulong InpSlippagePoints = 20; // Max slippage in points
input ulong InpMagicNumber = 101001; // EA Magic Number
//--- Global trade instance
CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Configure CTrade instance
trade.SetExpertMagicNumber(InpMagicNumber);
trade.SetDeviationInPoints(InpSlippagePoints);
trade.SetTypeFillingBySymbol(_Symbol);
trade.SetAsyncMode(false); // Synchronous request; still inspect server result
Print("CTrade initialized successfully. Magic: ", InpMagicNumber);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Helper: Open a long position using CTrade::Buy |
//+------------------------------------------------------------------+
bool OpenBuyOrder(double lots, int slPoints, int tpPoints, const string comment="Pineify Buy")
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double sl = (slPoints > 0) ? NormalizeDouble(ask - slPoints * point, digits) : 0.0;
double tp = (tpPoints > 0) ? NormalizeDouble(ask + tpPoints * point, digits) : 0.0;
// Call CTrade::Buy signature: (volume, symbol, price, sl, tp, comment)
if(trade.Buy(lots, _Symbol, ask, sl, tp, comment))
{
uint retcode = trade.ResultRetcode();
if(retcode == TRADE_RETCODE_DONE)
{
PrintFormat("Buy request completed. Order Ticket: %I64u, Deal: %I64u, Price: %.*f",
trade.ResultOrder(), trade.ResultDeal(), digits, ask);
return true;
}
PrintFormat("Buy returned true but retcode is %u (%s)",
retcode, trade.ResultRetcodeDescription());
return false;
}
PrintFormat("CTrade::Buy failed! Retcode: %u (%s)",
trade.ResultRetcode(), trade.ResultRetcodeDescription());
return false;
}
//+------------------------------------------------------------------+
//| Helper: Modify position stop loss and take profit |
//+------------------------------------------------------------------+
bool ModifyPositionSLTP(ulong ticket, double newSL, double newTP)
{
if(!PositionSelectByTicket(ticket) || PositionGetString(POSITION_SYMBOL)!=_Symbol ||
PositionGetInteger(POSITION_MAGIC)!=(long)InpMagicNumber) return false;
if(!trade.PositionModify(ticket, newSL, newTP) || trade.ResultRetcode()!=TRADE_RETCODE_DONE)
{
PrintFormat("PositionModify failed for ticket %I64u: %u (%s)",
ticket, trade.ResultRetcode(), trade.ResultRetcodeDescription());
return false;
}
PrintFormat("Position %I64u modified successfully to SL: %f, TP: %f",
ticket, newSL, newTP);
return true;
}
//+------------------------------------------------------------------+
//| Helper: Close position safely |
//+------------------------------------------------------------------+
bool CloseSpecificPosition(ulong ticket)
{
if(!PositionSelectByTicket(ticket) || PositionGetString(POSITION_SYMBOL)!=_Symbol ||
PositionGetInteger(POSITION_MAGIC)!=(long)InpMagicNumber) return false;
if(!trade.PositionClose(ticket) || trade.ResultRetcode()!=TRADE_RETCODE_DONE)
{
PrintFormat("PositionClose failed for ticket %I64u: %u (%s)",
ticket, trade.ResultRetcode(), trade.ResultRetcodeDescription());
return false;
}
PrintFormat("Position %I64u closed successfully", ticket);
return true;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
static bool attempted=false;
if(!AllowDemoOrder || attempted || AccountInfoInteger(ACCOUNT_TRADE_MODE)!=ACCOUNT_TRADE_MODE_DEMO) return;
if(PositionsTotal() == 0)
{
attempted=true; // Do not retry an ambiguous or rejected request automatically.
OpenBuyOrder(InpLotSize, InpStopLossPoints, InpTakeProfitPoints, "Pineify CTrade Demo");
}
}
Copy this code into MetaEditor, save it in your MQL5 folder (Experts, Scripts, or Include), and compile with F7.
Generate custom MQL5 code with Pineify AI
Describe the trade execution, indicator calculations, risk management, or data processing logic you need. Pineify generates editable MQL5 source code. Review its logic, request a syntax check, and compile and test the final file in MetaEditor.
Frequently Asked Questions
Related MQL5 pages
Technical references
Risk and testing note
These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.