Skip to content

✅ Getting Multiple Quotes

Request: retrieve the latest price snapshot for multiple symbols at once as QuoteManyData. Fastest way to fill UI tiles or pre‑validate orders across several instruments.

Source files (SDK):

  • MetaRpcMT4/mt4_account.py — method quote_many(...)
  • MetaRpcMT4/mt4_term_api_market_info_pb2.pyQuoteMany* and QuoteData

RPC

  • Service: mt4_term_api.MarketInfo
  • Method: QuoteMany(QuoteManyRequest) → QuoteManyReply
  • Low‑level client: MarketInfoStub.QuoteMany(request, metadata, timeout)
  • SDK wrapper: MT4Account.quote_many(symbols: list[str], deadline=None, cancellation_event=None) → QuoteManyData

Request message: QuoteManyRequest { symbols: string[] } Reply message: QuoteManyReply { data: QuoteManyData }


🔗 Code Example

# Fetch quotes for a basket of symbols
rows = await acct.quote_many(["EURUSD", "GBPUSD", "XAUUSD"])

# rows: QuoteManyData
# Common patterns (depending on pb schema):
# 1) If the reply contains .items with QuoteData objects in request order:
for q in rows.items:  # list[QuoteData]
    print(f"{q.symbol} bid={q.bid:.5f} ask={q.ask:.5f}")

# 2) If the reply contains name+quote tuples (e.g., SymbolNameInfos):
# for e in rows.SymbolNameInfos:  # list[ { symbolName, data: QuoteData, index } ]
#     q = e.data
#     print(f"{e.symbolName} bid={q.bid:.5f} ask={q.ask:.5f}")

Method Signature

async def quote_many(
    self,
    symbols: list[str],
    deadline: datetime | None = None,
    cancellation_event: asyncio.Event | None = None,
) -> market_info_pb2.QuoteManyData

💬 Just the essentials

  • What it is. A batched quote call that returns bid/ask + OHLC per symbol.
  • Why. Reduces round‑trips versus calling quote(...) repeatedly; keeps UI grids snappy.
  • Ordering. Reply typically preserves request order (via index or contiguous list semantics).

🔽 Input

Parameter Type Description
symbols list[str] Symbols to fetch, e.g., ["EURUSD","XAUUSD"].
deadline datetime | None Absolute per‑call deadline.
cancellation_event asyncio.Event | None Cooperative cancel for retry wrapper.

⬆️ Output

Payload: QuoteManyData

Field Type Description
quotes QuoteData[] Array of quotes in the same order as requested.

Each QuoteData element contains (from mt4_term_api_market_info_pb2.py):

  • symbol: string
  • bid: double, ask: double
  • high: double, low: double
  • date_time: google.protobuf.Timestamp

This RPC does not use method‑specific enums. Timeframe enums apply to quote_history(...), not to quote_many.


🎯 Purpose

Use this method to:

  • Populate price grids/tiles efficiently.
  • Validate SL/TP distances across a basket before submitting multiple orders.
  • Compute mid/spread metrics in bulk.

🧩 Notes & Tips

  • Wrapper uses execute_with_reconnect(...) for transient gRPC retries.
  • Keep the basket reasonable in hot paths; huge symbol lists will increase payload size and latency.
  • Combine with symbol_params_many(...) for digits/point/SL‑TP constraints and with tick_value_with_size(...) for money‑per‑tick conversions.

See also: quote(...) — single‑symbol snapshot. quote_history(...) — historical bars with timeframe enum. symbol_params_many(...) — constraints & trade/margin enums.


Usage Examples

1) Compact grid printer

rows = await acct.quote_many(["EURUSD","USDJPY","XAUUSD"])
# Variant A: contiguous items
for q in getattr(rows, 'items', []):
    print(f"{q.symbol:8} bid={q.bid:.5f} ask={q.ask:.5f}")

# Variant B: name+quote tuples
for e in getattr(rows, 'SymbolNameInfos', []):
    q = e.data
    print(f"{e.symbolName:8} bid={q.bid:.5f} ask={q.ask:.5f}")

2) Mid & spread per symbol

rows = await acct.quote_many(["EURUSD","GBPUSD"])  # batch

def handle_quote(q):
    mid = (q.bid + q.ask) / 2
    spread = getattr(q, 'spread', None)
    return mid, spread

if hasattr(rows, 'items'):
    stats = { q.symbol: handle_quote(q) for q in rows.items }
elif hasattr(rows, 'SymbolNameInfos'):
    stats = { e.symbolName: handle_quote(e.data) for e in rows.SymbolNameInfos }

print(stats)

3) Validate SL/TP distance for all symbols

# For each symbol: fetch params + quote; ensure planned SL distance >= StopsLevel
symbols = ["EURUSD","USDJPY","XAUUSD"]
qmany = await acct.quote_many(symbols)
params_all = await acct.symbol_params_many()  # beware: heavy; prefer single-symbol calls in hot paths

# Build a dict of StopsLevel/Point by symbol
pmap = { p.Symbol: p for p in params_all.params_info }

# Iterate quotes in either layout
def iter_quotes(reply):
    if hasattr(reply, 'items'):
        for q in reply.items:
            yield q.symbol, q
    else:
        for e in reply.SymbolNameInfos:
            yield e.symbolName, e.data

for sym, q in iter_quotes(qmany):
    p = pmap.get(sym)
    if not p:
        continue
    min_pts = max(p.StopsLevel, p.FreezeLevel)
    min_delta = min_pts * p.Point
    # Example: BUY SL must be at least min_delta below bid
    # sl_ok = (q.bid - planned_sl_distance) >= min_delta