Why Account and Market Information Functions Are Critical
Account and market information functions are the foundation of professional EA risk management. Without these functions, your EA cannot assess available capital, calculate proper position sizes, respect broker limits, or adapt to changing market conditions. Mastering these functions transforms your EA from a simple signal-follower into a robust risk-managed trading system.
Complete Account and Market Functions Reference Table
| Category | Function | Return Value | Primary Use |
|----------|----------|--------------|--------------|
| Account | AccountBalance() | double | Current account balance |
| Account | AccountEquity() | double | Current account equity (balance +浮动盈亏) |
| Account | AccountFreeMargin() | double | Free margin available for trading |
| Account | AccountMargin() | double | Used margin for open positions |
| Account | AccountLeverage() | int | Account leverage (e.g., 100:1) |
| Account | AccountProfit() | double | Total floating profit/loss |
| Account | AccountName() | string | Account holder name |
| Account | AccountNumber() | int | Account number |
| Account | AccountCurrency() | string | Account deposit currency |
| Market | Bid | double | Current bid price |
| Market | Ask | double | Current ask price |
| Market | Point | double | Point value (最小价格变动单位) |
| Market | Digits | int | Price decimal places |
| Market | MarketInfo() | double | Various market parameters |
| Market | TimeCurrent() | datetime | Current server time |
| Market | RefreshRates() | bool | Update Bid/Ask prices |
1. Account Information Functions - Knowing Your Trading Capital
```mql4
// Complete account information retrieval
void DisplayAccountInfo() {
Print("========== ACCOUNT INFORMATION ==========");
Print("Account Name: ", AccountName());
Print("Account Number: ", AccountNumber());
Print("Account Currency: ", AccountCurrency());
Print("Account Balance: ", DoubleToString(AccountBalance(), 2));
Print("Account Equity: ", DoubleToString(AccountEquity(), 2));
Print("Account Profit: ", DoubleToString(AccountProfit(), 2));
Print("Free Margin: ", DoubleToString(AccountFreeMargin(), 2));
Print("Used Margin: ", DoubleToString(AccountMargin(), 2));
Print("Margin Level: ", DoubleToString(AccountFreeMarginMode() == 0 ?
(AccountEquity()/AccountMargin())*100 : 0, 2), "%");
Print("Leverage: 1:", AccountLeverage());
Print("Stopout Mode: ", AccountStopoutMode() == 0 ? "Percent" : "Money");
Print("Stopout Level: ", AccountStopoutLevel());
Print("==========================================");
}
// Check if account has sufficient free margin for trade
bool HasSufficientMargin(double lotSize) {
double requiredMargin = MarketInfo(Symbol(), MODE_MARGINREQUIRED) * lotSize;
double freeMargin = AccountFreeMargin();
Print("Required margin: ", requiredMargin);
Print("Free margin: ", freeMargin);
return (freeMargin >= requiredMargin * 1.2); // 20% buffer
}
// Calculate maximum allowed lot size based on free margin
double GetMaxLotByMargin() {
double freeMargin = AccountFreeMargin();
double marginRequired = MarketInfo(Symbol(), MODE_MARGINREQUIRED);
if(marginRequired <= 0) return 0.01;
double maxLots = freeMargin / marginRequired;
double stepSize = MarketInfo(Symbol(), MODE_LOTSTEP);
double maxAllowed = MarketInfo(Symbol(), MODE_MAXLOT);
maxLots = MathFloor(maxLots / stepSize) * stepSize;
maxLots = MathMin(maxLots, maxAllowed);
return NormalizeDouble(maxLots, 2);
}
// Risk-based position sizing (percent of equity)
double CalculateLotByRiskPercent(double riskPercent, double stopLossPoints) {
double equity = AccountEquity();
double riskAmount = equity * riskPercent / 100;
double pointValue = MarketInfo(Symbol(), MODE_TICKVALUE);
if(pointValue <= 0 || stopLossPoints <= 0) return 0.01;
double rawLots = riskAmount / (stopLossPoints * pointValue);
double stepSize = MarketInfo(Symbol(), MODE_LOTSTEP);
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
rawLots = MathFloor(rawLots / stepSize) * stepSize;
rawLots = MathMax(minLot, MathMin(maxLot, rawLots));
return NormalizeDouble(rawLots, 2);
}
// Track daily loss limit
bool IsDailyLossExceeded(double maxDailyLossPercent) {
static double startEquity = 0;
static datetime lastReset = 0;
datetime currentDay = GetMidnight();
if(currentDay != lastReset) {
startEquity = AccountEquity();
lastReset = currentDay;
}
double currentEquity = AccountEquity();
double lossPercent = (startEquity - currentEquity) / startEquity * 100;
if(lossPercent >= maxDailyLossPercent) {
Print("Daily loss limit reached: ", lossPercent, "%");
return true;
}
return false;
}
// Get midnight timestamp
datetime GetMidnight() {
MqlDateTime tm;
TimeToStruct(TimeCurrent(), tm);
tm.hour = 0;
tm.min = 0;
tm.sec = 0;
return StructToTime(tm);
}
```
2. Market Information Functions (MarketInfo) - Understanding Trading Conditions
```mql4
// Complete MarketInfo parameter reference
void DisplayMarketInfo() {
Print("========== MARKET INFORMATION ==========");
Print("Symbol: ", Symbol());
Print("Bid: ", DoubleToString(Bid, Digits));
Print("Ask: ", DoubleToString(Ask, Digits));
Print("Spread: ", MarketInfo(Symbol(), MODE_SPREAD));
Print("Point: ", DoubleToString(Point, 5));
Print("Digits: ", Digits);
Print("Tick Size: ", MarketInfo(Symbol(), MODE_TICKSIZE));
Print("Tick Value: ", MarketInfo(Symbol(), MODE_TICKVALUE));
Print("Min Lot: ", MarketInfo(Symbol(), MODE_MINLOT));
Print("Max Lot: ", MarketInfo(Symbol(), MODE_MAXLOT));
Print("Lot Step: ", MarketInfo(Symbol(), MODE_LOTSTEP));
Print("Stop Level: ", MarketInfo(Symbol(), MODE_STOPLEVEL));
Print("Freeze Level: ", MarketInfo(Symbol(), MODE_FREEZELEVEL));
Print("Margin Required: ", MarketInfo(Symbol(), MODE_MARGINREQUIRED));
Print("========================================");
}
// MarketInfo parameter constants reference
/*
MODE_LOW - Low price of current day
MODE_HIGH - High price of current day
MODE_TIME - Last server time
MODE_BID - Current bid price
MODE_ASK - Current ask price
MODE_POINT - Point value
MODE_DIGITS - Price decimal places
MODE_SPREAD - Current spread in points
MODE_STOPLEVEL - Minimum stop distance in points
MODE_FREEZELEVEL - Order freeze distance in points
MODE_LOTSIZE - Lot size in base currency
MODE_TICKVALUE - Tick value in deposit currency
MODE_TICKSIZE - Tick size
MODE_SWAPLONG - Long swap rate
MODE_SWAPSHORT - Short swap rate
MODE_STARTING - Starting date of market
MODE_EXPIRATION - Expiration date of market
MODE_TRADEALLOWED - Trading allowed for symbol
MODE_MINLOT - Minimum lot size
MODE_MAXLOT - Maximum lot size
MODE_LOTSTEP - Lot size step
MODE_MARGINREQUIRED - Margin required per lot
MODE_MARGINCALCMODE - Margin calculation mode
*/
// Check if spread is acceptable for trading
bool IsSpreadAcceptable(int maxSpread) {
int currentSpread = (int)MarketInfo(Symbol(), MODE_SPREAD);
if(currentSpread <= maxSpread) {
return true;
}
Print("Spread too high: ", currentSpread, " (max: ", maxSpread, ")");
return false;
}
// Validate stop loss distance
bool IsStopLossValid(double stopLossPrice, int orderType) {
double currentPrice = (orderType == OP_BUY) ? Ask : Bid;
int minDistance = (int)MarketInfo(Symbol(), MODE_STOPLEVEL);
double distance = (orderType == OP_BUY) ?
(currentPrice - stopLossPrice) / Point() :
(stopLossPrice - currentPrice) / Point();
if(distance >= minDistance) {
return true;
}
Print("Stop loss too close: ", distance, " (min: ", minDistance, ")");
return false;
}
// Get optimal lot size respecting broker limits
double GetValidLotSize(double requestedLot) {
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double stepSize = MarketInfo(Symbol(), MODE_LOTSTEP);
// Clamp to min/max
double validLot = MathMax(minLot, MathMin(maxLot, requestedLot));
// Round to step size
validLot = MathFloor(validLot / stepSize) * stepSize;
validLot = NormalizeDouble(validLot, 2);
Print("Requested lot: ", requestedLot, " -> Valid lot: ", validLot);
return validLot;
}
// Calculate required margin for position
double CalculateRequiredMargin(double lotSize) {
double marginPerLot = MarketInfo(Symbol(), MODE_MARGINREQUIRED);
double totalMargin = marginPerLot * lotSize;
Print("Margin required for ", lotSize, " lots: ", totalMargin);
return totalMargin;
}
// Calculate tick value in account currency
double GetTickValue() {
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
return tickValue;
}
// Calculate point value in account currency
double CalculatePointValue(double lotSize) {
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double pointValue = tickValue * lotSize;
return pointValue;
}
```
3. Bid/Ask/Point/Digits - Real-Time Price Access
```mql4
// Refresh rates before trading (CRITICAL)
void RefreshTradingRates() {
RefreshRates(); // Updates Bid and Ask variables
Print("Refreshed rates - Bid: ", DoubleToString(Bid, Digits),
" Ask: ", DoubleToString(Ask, Digits));
}
// Professional order execution with rate refresh
int ExecuteOrderWithRefresh(int orderType, double lotSize, double stopLossPoints, double takeProfitPoints) {
// ALWAYS refresh rates before OrderSend
RefreshRates();
double price = (orderType == OP_BUY) ? Ask : Bid;
int digits = Digits;
int stopLevel = (int)MarketInfo(Symbol(), MODE_STOPLEVEL);
double sl = 0, tp = 0;
if(stopLossPoints > 0) {
if(orderType == OP_BUY) {
sl = NormalizeDouble(price - MathMax(stopLossPoints, stopLevel) * Point, digits);
} else {
sl = NormalizeDouble(price + MathMax(stopLossPoints, stopLevel) * Point, digits);
}
}
if(takeProfitPoints > 0) {
if(orderType == OP_BUY) {
tp = NormalizeDouble(price + takeProfitPoints * Point, digits);
} else {
tp = NormalizeDouble(price - takeProfitPoints * Point, digits);
}
}
int ticket = OrderSend(Symbol(), orderType, lotSize, price, 30, sl, tp, "Price EA", 12345, 0, clrNONE);
return ticket;
}
// Calculate profit/loss in points
double CalculateProfitInPoints(double entryPrice, double exitPrice, int orderType) {
double points;
if(orderType == OP_BUY) {
points = (exitPrice - entryPrice) / Point;
} else {
points = (entryPrice - exitPrice) / Point;
}
return points;
}
// Calculate profit/loss in account currency
double CalculateProfitInCurrency(double entryPrice, double exitPrice, double lotSize, int orderType) {
double points = CalculateProfitInPoints(entryPrice, exitPrice, orderType);
double pointValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double profit = points * pointValue * lotSize;
return profit;
}
```
4. Complete Risk Management System
```mql4
//+------------------------------------------------------------------+
//| Complete Risk Management System |
//+------------------------------------------------------------------+
class RiskManager {
private:
int magicNumber;
double maxDailyLossPercent;
double maxDrawdownPercent;
int maxDailyTrades;
int maxConcurrentPositions;
double maxRiskPerTradePercent;
int todayTrades;
double startingEquity;
datetime lastReset;
void ResetDaily() {
datetime midnight = GetMidnight();
if(midnight != lastReset) {
startingEquity = AccountEquity();
todayTrades = 0;
lastReset = midnight;
Print("RiskManager: Daily counters reset. Starting equity: ", startingEquity);
}
}
datetime GetMidnight() {
MqlDateTime tm;
TimeToStruct(TimeCurrent(), tm);
tm.hour = 0;
tm.min = 0;
tm.sec = 0;
return StructToTime(tm);
}
public:
RiskManager(int magic) {
magicNumber = magic;
maxDailyLossPercent = 5.0;
maxDrawdownPercent = 15.0;
maxDailyTrades = 10;
maxConcurrentPositions = 3;
maxRiskPerTradePercent = 2.0;
todayTrades = 0;
startingEquity = AccountEquity();
lastReset = GetMidnight();
}
void SetMaxDailyLossPercent(double percent) { maxDailyLossPercent = percent; }
void SetMaxDrawdownPercent(double percent) { maxDrawdownPercent = percent; }
void SetMaxDailyTrades(int trades) { maxDailyTrades = trades; }
void SetMaxConcurrentPositions(int positions) { maxConcurrentPositions = positions; }
void SetMaxRiskPerTradePercent(double percent) { maxRiskPerTradePercent = percent; }
bool CanTrade() {
ResetDaily();
// Check daily loss limit
double currentEquity = AccountEquity();
double lossPercent = (startingEquity - currentEquity) / startingEquity * 100;
if(lossPercent >= maxDailyLossPercent) {
Print("RiskManager: Daily loss limit reached. Loss: ", lossPercent, "%");
return false;
}
// Check daily trade count
if(todayTrades >= maxDailyTrades) {
Print("RiskManager: Daily trade limit reached. Trades: ", todayTrades);
return false;
}
// Check concurrent positions
int openPositions = CountOpenPositions();
if(openPositions >= maxConcurrentPositions) {
Print("RiskManager: Max concurrent positions reached. Positions: ", openPositions);
return false;
}
// Check drawdown
double peakEquity = GetPeakEquity();
double drawdownPercent = (peakEquity - currentEquity) / peakEquity * 100;
if(drawdownPercent >= maxDrawdownPercent) {
Print("RiskManager: Max drawdown reached. Drawdown: ", drawdownPercent, "%");
return false;
}
// Check free margin
double freeMargin = AccountFreeMargin();
double minMarginRequired = freeMargin * 0.2; // Keep 20% buffer
if(freeMargin < minMarginRequired) {
Print("RiskManager: Insufficient free margin. Free: ", freeMargin);
return false;
}
return true;
}
double CalculateLotSize(double stopLossPoints) {
double equity = AccountEquity();
double riskAmount = equity * maxRiskPerTradePercent / 100;
double pointValue = MarketInfo(Symbol(), MODE_TICKVALUE);
if(pointValue <= 0 || stopLossPoints <= 0) return 0.01;
double rawLots = riskAmount / (stopLossPoints * pointValue);
double stepSize = MarketInfo(Symbol(), MODE_LOTSTEP);
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
rawLots = MathFloor(rawLots / stepSize) * stepSize;
rawLots = MathMax(minLot, MathMin(maxLot, rawLots));
return NormalizeDouble(rawLots, 2);
}
void RecordTrade() {
todayTrades++;
Print("RiskManager: Trade recorded. Daily total: ", todayTrades);
}
int CountOpenPositions() {
int count = 0;
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderMagicNumber() == magicNumber && OrderSymbol() == Symbol()) {
count++;
}
}
}
return count;
}
double GetPeakEquity() {
static double peakEquity = 0;
double currentEquity = AccountEquity();
if(currentEquity > peakEquity) {
peakEquity = currentEquity;
}
return peakEquity;
}
void PrintStatus() {
Print("========== RISK MANAGER STATUS ==========");
Print("Balance: ", DoubleToString(AccountBalance(), 2));
Print("Equity: ", DoubleToString(AccountEquity(), 2));
Print("Free Margin: ", DoubleToString(AccountFreeMargin(), 2));
Print("Daily Loss: ", DoubleToString((startingEquity - AccountEquity())/startingEquity*100, 2), "%");
Print("Daily Trades: ", todayTrades, "/", maxDailyTrades);
Print("Open Positions: ", CountOpenPositions(), "/", maxConcurrentPositions);
Print("==========================================");
}
};
```
5. Complete EA with Risk Management
```mql4
//+------------------------------------------------------------------+
//| RiskManagedEA.mq4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property version "1.00"
#property strict
input double InpRiskPercent = 2.0;
input int InpMagic = 12345;
input int InpMaxSpread = 30;
input int InpTrailingStop = 30;
RiskManager riskMgr(InpMagic);
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
riskMgr.SetMaxDailyLossPercent(5.0);
riskMgr.SetMaxDailyTrades(10);
riskMgr.SetMaxConcurrentPositions(3);
riskMgr.SetMaxRiskPerTradePercent(InpRiskPercent);
Print("Risk Managed EA initialized");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
static datetime lastBarTime = 0;
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];
// Apply trailing stop to existing positions
ManageExistingPositions();
// Check if we can trade
if(!riskMgr.CanTrade()) {
riskMgr.PrintStatus();
return;
}
// Check spread
if(!IsSpreadAcceptable(InpMaxSpread)) {
return;
}
// Generate signal
int signal = GenerateSignal();
if(signal == SIGNAL_BUY) {
ExecuteTrade(OP_BUY);
} else if(signal == SIGNAL_SELL) {
ExecuteTrade(OP_SELL);
}
}
//+------------------------------------------------------------------+
//| Execute trade with risk management |
//+------------------------------------------------------------------+
void ExecuteTrade(int orderType) {
RefreshRates();
double stopLossPoints = 50;
double lotSize = riskMgr.CalculateLotSize(stopLossPoints);
if(lotSize <= 0) {
Print("Invalid lot size calculated");
return;
}
double price = (orderType == OP_BUY) ? Ask : Bid;
double sl = 0, tp = 0;
int digits = Digits;
int stopLevel = (int)MarketInfo(Symbol(), MODE_STOPLEVEL);
if(orderType == OP_BUY) {
sl = NormalizeDouble(price - MathMax(stopLossPoints, stopLevel) * Point, digits);
tp = NormalizeDouble(price + 100 * Point, digits);
} else {
sl = NormalizeDouble(price + MathMax(stopLossPoints, stopLevel) * Point, digits);
tp = NormalizeDouble(price - 100 * Point, digits);
}
int ticket = OrderSend(Symbol(), orderType, lotSize, price, 30, sl, tp, "RiskManaged EA", InpMagic, 0, clrNONE);
if(ticket > 0) {
riskMgr.RecordTrade();
Print("Order opened: ", ticket, " Lot: ", lotSize);
} else {
Print("Order failed. Error: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Manage existing positions with trailing stop |
//+------------------------------------------------------------------+
void ManageExistingPositions() {
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderMagicNumber() == InpMagic && OrderSymbol() == Symbol()) {
ApplyTrailingStop(OrderTicket());
}
}
}
}
//+------------------------------------------------------------------+
//| Apply trailing stop |
//+------------------------------------------------------------------+
void ApplyTrailingStop(int ticket) {
if(!OrderSelect(ticket, SELECT_BY_TICKET)) return;
double openPrice = OrderOpenPrice();
double currentStop = OrderStopLoss();
double currentPrice = (OrderType() == OP_BUY) ? Bid : Ask;
double newStop = 0;
if(OrderType() == OP_BUY) {
double profitPoints = (currentPrice - openPrice) / Point;
if(profitPoints > InpTrailingStop) {
newStop = NormalizeDouble(currentPrice - InpTrailingStop * Point, Digits);
}
} else {
double profitPoints = (openPrice - currentPrice) / Point;
if(profitPoints > InpTrailingStop) {
newStop = NormalizeDouble(currentPrice + InpTrailingStop * Point, Digits);
}
}
if(newStop > 0 && newStop != currentStop) {
OrderModify(ticket, openPrice, newStop, OrderTakeProfit(), 0, clrNONE);
}
}
//+------------------------------------------------------------------+
//| Check if spread is acceptable |
//+------------------------------------------------------------------+
bool IsSpreadAcceptable(int maxSpread) {
int spread = (int)MarketInfo(Symbol(), MODE_SPREAD);
if(spread <= maxSpread) return true;
Print("Spread too high: ", spread);
return false;
}
```
Account and Market Functions Best Practices Checklist
Reference:
9. Next Step
Part 15 will explain Common MQL4 Compilation Errors and Solutions – Complete guide to fixing errors 1, 17, 30, 31, 33, 130, 4051 and more with practical debugging techniques.