🔢 RoundVolumePrice (GoMT4)¶
Goal: correctly round volume (lots) and price values according to symbol parameters (Digits, VolumeStep, Min/Max lot). This avoids broker rejections when sending/modifying orders.
Real code refs:
- Account:
examples/mt4/MT4Account.go(SymbolParamsprovides Digits, VolumeStep, Min/Max, Point)- Demos:
examples/mt4/MT4_service.go(order send/modify examples use these params)
✅ Why we need this¶
- Brokers only accept volumes that are multiples of
VolumeStepand within[MinLot, MaxLot]. - Prices must be rounded to the symbol’s
Digits(e.g., 5‑digit EURUSD → 1.23456). - If you don’t align values,
OrderSendorOrderModifywill return an error (invalid volume/price).
🔎 1) Read params first¶
p, err := account.SymbolParams(ctx, symbol)
if err != nil { return err }
fmt.Printf("%s Digits=%d VolumeStep=%.2f MinLot=%.2f MaxLot=%.2f\n",
symbol, p.GetDigits(), p.GetVolumeStep(), p.GetVolumeMin(), p.GetVolumeMax())
🧮 2) Helpers (convenience functions)¶
⚠️ Note: these helpers are not auto‑generated by pb, but are commonly added in projects like this one. If you don’t yet have them in your repo, you can safely add them in utils.go (or similar). They simply apply the parameters you already fetch with SymbolParams.
func AlignVolume(v, step, min, max float64) float64 {
if step <= 0 { return v }
v = math.Floor(v/step+0.5) * step
if v < min { v = min }
if v > max { v = max }
return v
}
func RoundPrice(p float64, digits int) float64 {
mul := math.Pow10(digits)
return math.Round(p*mul) / mul
}
Usage:
vol := AlignVolume(0.13, p.GetVolumeStep(), p.GetVolumeMin(), p.GetVolumeMax())
price := RoundPrice(1.092345, int(p.GetDigits()))
📝 3) Use in OrderSend¶
side := pb.OrderSendOperationType_OC_OP_BUY
vol := AlignVolume(0.13, p.GetVolumeStep(), p.GetVolumeMin(), p.GetVolumeMax())
price := RoundPrice(q.GetAsk(), int(p.GetDigits()))
resp, err := account.OrderSend(ctx, symbol, side, vol, &price, &slip, nil, nil, &comment, &magic, nil)
if err != nil {
return fmt.Errorf("OrderSend failed: %w", err)
}
⚠️ Pitfalls¶
- Skipping rounding → broker rejects with “invalid price/volume”.
- Wrong Digits → always take from
SymbolParams, not from hardcoded assumptions. - Different brokers →
VolumeStepcan differ (0.01 vs 0.1) andMinLot/MaxLotvary.
📎 See also¶
SymbolParams.md— explains where Digits/LotStep come from.PlaceMarketOrder.md,PlacePendingOrder.md— show real order placement using these helpers.ModifyOrder.md— reusesRoundPricefor SL/TP adjustments.