✅ OrderCalcMargin¶
Request: Calculate required margin for an order before placing it.
API Information:
- Low-level API:
MT5Account.OrderCalcMargin(...)(from Go packagegithub.com/MetaRPC/GoMT5/package/Helpers) - gRPC service:
mt5_term_api.TradeFunctions - Proto definition:
OrderCalcMargin(defined inmt5-term-api-trade-functions.proto)
💬 Just the essentials¶
- What it is. Pre-calculates margin requirement before order placement without actually placing the order.
- Why you need it. Verify sufficient account margin before trading to avoid "Not enough money" rejections.
- Risk management. Essential for position sizing and account safety - calculate maximum safe lot size based on available margin.
🎯 Purpose¶
Use it to:
- Check margin requirements before placing orders
- Calculate maximum position size based on available free margin
- Validate trading parameters in risk management systems
- Display margin requirements in trading UI/dashboard
- Prevent order rejections due to insufficient margin
📚 Tutorial¶
For a detailed line-by-line explanation with examples, see: → OrderCalcMargin - How it works
RPC¶
- Service:
mt5_term_api.TradeFunctions - Method:
OrderCalcMargin(OrderCalcMarginRequest) → OrderCalcMarginReply - Low‑level client (generated):
TradeFunctionsClient.OrderCalcMargin(ctx, request, opts...)
// OrderCalcMargin calculates required margin for an order.
//
// Use this method to determine how much margin will be required before placing an order.
//
// Parameters:
// - ctx: Context for timeout and cancellation control
// - req: OrderCalcMarginRequest with Action, Symbol, Volume, and Price
//
// Returns OrderCalcMarginData with Margin value in account currency.
func (a *MT5Account) OrderCalcMargin(
ctx context.Context,
req *pb.OrderCalcMarginRequest,
) (*pb.OrderCalcMarginData, error)
Request message: OrderCalcMarginRequest
Reply message: OrderCalcMarginReply { oneof response { OrderCalcMarginData data = 1; Error error = 2; } }
🔽 Input¶
| Parameter | Type | Description |
|---|---|---|
ctx |
context.Context |
Context for deadline/timeout and cancellation |
req |
*pb.OrderCalcMarginRequest |
Request with Action, Symbol, Volume, and Price |
OrderCalcMarginRequest fields:
| Field | Type | Required | Description |
|---|---|---|---|
Symbol |
string |
✅ | Trading instrument name (e.g., "EURUSD") |
OrderType |
ENUM_ORDER_TYPE_TF |
✅ | Order type: ORDER_TYPE_TF_BUY (0), ORDER_TYPE_TF_SELL (1), etc |
Volume |
double |
✅ | Trade volume in lots |
OpenPrice |
double |
✅ | Order price (use current market price for market orders) |
⬆️ Output — OrderCalcMarginData¶
| Field | Type | Description |
|---|---|---|
Margin |
double |
Required margin in account currency |
💡 Enum Usage Note: The tables show simplified constant names for readability. In Go code, use full names with the enum type prefix.
Format:
pb.<ENUM_TYPE>_<CONSTANT_NAME>Example:
pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_BUY
📘 Enum: ENUM_ORDER_TYPE_TF¶
| Value | Constant | Description |
|---|---|---|
| 0 | ORDER_TYPE_TF_BUY |
Market Buy order |
| 1 | ORDER_TYPE_TF_SELL |
Market Sell order |
| 2 | ORDER_TYPE_TF_BUY_LIMIT |
Buy Limit pending order |
| 3 | ORDER_TYPE_TF_SELL_LIMIT |
Sell Limit pending order |
| 4 | ORDER_TYPE_TF_BUY_STOP |
Buy Stop pending order |
| 5 | ORDER_TYPE_TF_SELL_STOP |
Sell Stop pending order |
| 6 | ORDER_TYPE_TF_BUY_STOP_LIMIT |
Upon reaching the order price, a pending Buy Limit order is placed at the StopLimit price |
| 7 | ORDER_TYPE_TF_SELL_STOP_LIMIT |
Upon reaching the order price, a pending Sell Limit order is placed at the StopLimit price |
| 8 | ORDER_TYPE_TF_CLOSE_BY |
Order to close a position by an opposite one |
🧩 Notes & Tips¶
- Automatic reconnection: All
MT5Accountmethods have built-in protection against transient gRPC errors with automatic reconnection viaExecuteWithReconnect. - Default timeout: If context has no deadline, a default
5stimeout is applied automatically. - Nil context: If you pass
nilcontext,context.Background()is used automatically. - Price parameter: For market orders, use current bid/ask price. For pending orders, use the intended order price.
- Hedging vs Netting: Margin calculation depends on account margin calculation mode (hedging or netting).
- Leverage consideration: Result accounts for account leverage and symbol-specific margin requirements.
🔗 Usage Examples¶
1) Basic margin calculation for market order¶
package main
import (
"context"
"fmt"
"time"
pb "github.com/MetaRPC/GoMT5/package"
"github.com/MetaRPC/GoMT5/package/Helpers"
)
func main() {
account := mt5.NewMT5Account("user", "password", "server:443")
err := account.Connect()
if err != nil {
panic(err)
}
defer account.Close()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Calculate margin for buying 0.1 lots of EURUSD at current price
marginData, err := account.OrderCalcMargin(ctx, &pb.OrderCalcMarginRequest{
Symbol: "EURUSD",
OrderType: pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_BUY,
Volume: 0.1,
OpenPrice: 1.10000, // Current ask price
})
if err != nil {
panic(err)
}
fmt.Printf("Required margin: %.2f USD\n", marginData.Margin)
// Output: Required margin: 110.00 USD
}
2) Check if account has enough margin¶
func CanOpenPosition(account *mt5.MT5Account, symbol string, volume float64, price float64) (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Get account summary to check free margin
summary, err := account.AccountSummary(ctx, &pb.AccountSummaryRequest{})
if err != nil {
return false, err
}
freeMargin := summary.AccountEquity - summary.AccountBalance // Simplified
// Calculate required margin
marginData, err := account.OrderCalcMargin(ctx, &pb.OrderCalcMarginRequest{
Symbol: symbol,
OrderType: pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_BUY,
Volume: volume,
OpenPrice: price,
})
if err != nil {
return false, err
}
fmt.Printf("Free margin: %.2f\n", freeMargin)
fmt.Printf("Required margin: %.2f\n", marginData.Margin)
return freeMargin >= marginData.Margin, nil
}
3) Calculate maximum safe lot size¶
func MaxSafeLotSize(account *mt5.MT5Account, symbol string, price float64, maxMarginUsagePercent float64) (float64, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Get account equity
summary, err := account.AccountSummary(ctx, &pb.AccountSummaryRequest{})
if err != nil {
return 0, err
}
maxAllowedMargin := summary.AccountEquity * (maxMarginUsagePercent / 100.0)
// Test with 1.0 lot to get margin per lot
testMargin, err := account.OrderCalcMargin(ctx, &pb.OrderCalcMarginRequest{
Symbol: symbol,
OrderType: pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_BUY,
Volume: 1.0,
OpenPrice: price,
})
if err != nil {
return 0, err
}
marginPerLot := testMargin.Margin
maxLots := maxAllowedMargin / marginPerLot
fmt.Printf("Account equity: %.2f\n", summary.AccountEquity)
fmt.Printf("Max allowed margin (%.0f%%): %.2f\n", maxMarginUsagePercent, maxAllowedMargin)
fmt.Printf("Margin per 1.0 lot: %.2f\n", marginPerLot)
fmt.Printf("Max safe lot size: %.2f\n", maxLots)
return maxLots, nil
}
// Usage:
// maxLots, err := MaxSafeLotSize(account, "EURUSD", 1.10000, 20.0) // Use max 20% of equity
4) Compare margin for buy vs sell¶
func CompareMarginBuySell(account *mt5.MT5Account, symbol string, volume float64, bidPrice, askPrice float64) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Calculate margin for BUY
buyMargin, err := account.OrderCalcMargin(ctx, &pb.OrderCalcMarginRequest{
Symbol: symbol,
OrderType: pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_BUY,
Volume: volume,
OpenPrice: askPrice,
})
if err != nil {
fmt.Printf("Buy margin error: %v\n", err)
return
}
// Calculate margin for SELL
sellMargin, err := account.OrderCalcMargin(ctx, &pb.OrderCalcMarginRequest{
Symbol: symbol,
OrderType: pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_SELL,
Volume: volume,
OpenPrice: bidPrice,
})
if err != nil {
fmt.Printf("Sell margin error: %v\n", err)
return
}
fmt.Printf("Symbol: %s, Volume: %.2f\n", symbol, volume)
fmt.Printf("BUY margin (at %.5f): %.2f\n", askPrice, buyMargin.Margin)
fmt.Printf("SELL margin (at %.5f): %.2f\n", bidPrice, sellMargin.Margin)
fmt.Printf("Difference: %.2f\n", buyMargin.Margin-sellMargin.Margin)
}
5) Batch margin calculation for multiple symbols¶
func CalculateMarginForPortfolio(account *mt5.MT5Account, positions []struct {
Symbol string
Volume float64
Price float64
}) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
totalMargin := 0.0
for _, pos := range positions {
marginData, err := account.OrderCalcMargin(ctx, &pb.OrderCalcMarginRequest{
Symbol: pos.Symbol,
OrderType: pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_BUY,
Volume: pos.Volume,
OpenPrice: pos.Price,
})
if err != nil {
fmt.Printf("Error for %s: %v\n", pos.Symbol, err)
continue
}
fmt.Printf("%s (%.2f lots): %.2f\n", pos.Symbol, pos.Volume, marginData.Margin)
totalMargin += marginData.Margin
}
fmt.Printf("\nTotal required margin: %.2f\n", totalMargin)
}
// Usage:
// CalculateMarginForPortfolio(account, []struct {
// Symbol string
// Volume float64
// Price float64
// }{
// {"EURUSD", 0.1, 1.10000},
// {"GBPUSD", 0.05, 1.27000},
// {"USDJPY", 0.08, 150.500},
// })
6) Margin calculation with error handling¶
func SafeMarginCheck(account *mt5.MT5Account, symbol string, volume float64, price float64) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
marginData, err := account.OrderCalcMargin(ctx, &pb.OrderCalcMarginRequest{
Symbol: symbol,
OrderType: pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_BUY,
Volume: volume,
OpenPrice: price,
})
if err != nil {
// Handle specific errors
if ctx.Err() == context.DeadlineExceeded {
fmt.Println("Request timeout - server may be slow")
} else {
fmt.Printf("Margin calculation failed: %v\n", err)
}
return
}
// Validate result
if marginData.Margin <= 0 {
fmt.Printf("Warning: Invalid margin value: %.2f\n", marginData.Margin)
return
}
fmt.Printf("Required margin: %.2f\n", marginData.Margin)
// Get account info for comparison
summary, err := account.AccountSummary(ctx, &pb.AccountSummaryRequest{})
if err != nil {
fmt.Printf("Failed to get account info: %v\n", err)
return
}
marginLevel := (summary.AccountEquity / marginData.Margin) * 100.0
fmt.Printf("Margin level after order: %.2f%%\n", marginLevel)
if marginLevel < 200 {
fmt.Println("Warning: Low margin level!")
}
}
🔧 Common Patterns¶
Pre-trade validation¶
func ValidateTradeMargin(account *mt5.MT5Account, symbol string, volume float64, price float64, minMarginLevel float64) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Get required margin
marginData, err := account.OrderCalcMargin(ctx, &pb.OrderCalcMarginRequest{
Symbol: symbol,
OrderType: pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_BUY,
Volume: volume,
OpenPrice: price,
})
if err != nil {
return fmt.Errorf("margin calculation failed: %w", err)
}
// Get account state
summary, err := account.AccountSummary(ctx, &pb.AccountSummaryRequest{})
if err != nil {
return fmt.Errorf("account summary failed: %w", err)
}
// Calculate margin level after trade
newMarginLevel := (summary.AccountEquity / marginData.Margin) * 100.0
if newMarginLevel < minMarginLevel {
return fmt.Errorf("insufficient margin: level would be %.2f%% (min: %.2f%%)",
newMarginLevel, minMarginLevel)
}
return nil
}
Dynamic lot size calculator¶
func CalculateLotSizeByRisk(account *mt5.MT5Account, symbol string, price float64, riskPercent float64) (float64, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
summary, err := account.AccountSummary(ctx, &pb.AccountSummaryRequest{})
if err != nil {
return 0, err
}
maxRiskAmount := summary.AccountEquity * (riskPercent / 100.0)
// Test with small volume to get margin requirement
testMargin, err := account.OrderCalcMargin(ctx, &pb.OrderCalcMarginRequest{
Symbol: symbol,
OrderType: pb.ENUM_ORDER_TYPE_TF_ORDER_TYPE_TF_BUY,
Volume: 0.01,
OpenPrice: price,
})
if err != nil {
return 0, err
}
marginPer001Lot := testMargin.Margin
lots := (maxRiskAmount / marginPer001Lot) * 0.01
return lots, nil
}
📚 See Also¶
- OrderCalcProfit - Calculate potential profit for a trade
- OrderCheck - Validate complete order before sending
- OrderSend - Place market or pending order
- AccountSummary - Get account balance and equity
- SymbolInfoMarginRate - Get margin requirements for order types