Stream Real-Time Symbol Ticks¶
Request: subscribe to real-time tick data for specified symbols.
API Information:
- Python API:
MT5Account.on_symbol_tick(...)(defined inpackage/MetaRpcMT5/helpers/mt5_account.py) - gRPC service:
mt5_term_api.SubscriptionService - Proto definition:
OnSymbolTick(defined inmt5-term-api-subscriptions.proto)
RPC¶
- Service:
mt5_term_api.SubscriptionService - Method:
OnSymbolTick(OnSymbolTickRequest) -> stream OnSymbolTickReply - Low-level client (generated):
SubscriptionServiceStub.OnSymbolTick(request, metadata)
💬 Just the essentials¶
- What it is. Real-time stream of price ticks for specified symbols.
- Why you need it. Monitor live prices, implement tick-based strategies, track market movements.
- High frequency. Can generate many updates per second during active trading.
🎯 Purpose¶
Use it to:
- Monitor real-time price changes for symbols
- Implement tick-based trading strategies
- Track bid/ask spreads in real-time
- Build live price dashboards
- Detect price movements immediately
- Collect tick data for analysis
from MetaRpcMT5 import MT5Account
class MT5Account:
# ...
async def on_symbol_tick(
self,
symbols: list[str],
cancellation_event: Optional[asyncio.Event] = None,
):
"""
Subscribes to real-time tick data for specified symbols.
Yields:
OnSymbolTickData: Async stream of tick data responses.
"""
Request message:
message OnSymbolTickRequest {
repeated string symbol_names = 1; // List of symbols to subscribe to
}
🔽 Input¶
| Parameter | Type | Description |
|---|---|---|
symbols |
list[str] |
Symbol names to subscribe to (e.g., ["EURUSD", "GBPUSD"]) |
cancellation_event |
Optional[asyncio.Event] |
Event to cancel streaming (optional) |
⬆️ Output - Async Generator¶
Returns an async generator that yields OnSymbolTickData objects.
OnSymbolTickData fields:
| Field | Type | Description |
|---|---|---|
symbol_tick |
MrpcSubscriptionMqlTick |
Tick data (see below) |
terminal_instance_guid_id |
str |
Terminal instance identifier |
MrpcSubscriptionMqlTick fields:
| Field | Type | Description |
|---|---|---|
symbol |
str |
Symbol name |
time |
google.protobuf.Timestamp |
Time of last price update |
time_msc |
int64 |
Time of last price update (milliseconds) |
bid |
float64 |
Current Bid price |
ask |
float64 |
Current Ask price |
last |
float64 |
Price of last deal (Last) |
volume |
uint64 |
Volume for the current Last price |
volume_real |
float64 |
Volume for the current Last price (real) |
flags |
uint32 |
Tick flags (buy/sell indication) |
📚 Tutorial¶
For a detailed line-by-line explanation with examples, see: OnSymbolTick - How it works
🧩 Notes & Tips¶
- Automatic reconnection: All
MT5Accountstreaming methods have built-in protection against transient gRPC errors with automatic reconnection viaexecute_stream_with_reconnect. - Async generator: The method returns an async generator - use
async forto consume data. - Multiple symbols: You can subscribe to multiple symbols in a single stream.
- Cancellation: Pass an
asyncio.Eventand callevent.set()to stop the stream gracefully. - High frequency: Tick streams can be very high frequency - ensure your processing is efficient.
- Resource management: Always cancel streams when done to free resources.
- Error handling: Errors are raised as exceptions - wrap in try/except for error handling.
- UUID handling: The terminal instance UUID is auto-generated by the server if not provided.
For explicit control (e.g., in streaming scenarios), pass
id_=uuid4()to constructor.
🔗 Usage Examples¶
1) Monitor live ticks for EURUSD¶
import asyncio
from MetaRpcMT5 import MT5Account
async def monitor_ticks():
account = MT5Account(
user=12345,
password="password",
grpc_server="mt5.mrpc.pro:443"
)
await account.connect_by_server_name(
server_name="YourBroker-Demo",
base_chart_symbol="EURUSD"
)
try:
# Subscribe to EURUSD ticks
async for tick_data in account.on_symbol_tick(symbols=["EURUSD"]):
tick = tick_data.symbol_tick
print(f"{tick.symbol}: Bid={tick.bid:.5f}, Ask={tick.ask:.5f}, "
f"Spread={tick.ask - tick.bid:.5f}")
except KeyboardInterrupt:
print("Stopping tick stream...")
finally:
await account.channel.close()
# Run
asyncio.run(monitor_ticks())
2) Monitor multiple symbols with cancellation¶
import asyncio
from MetaRpcMT5 import MT5Account
async def monitor_multiple_symbols():
account = MT5Account(
user=12345,
password="password",
grpc_server="mt5.mrpc.pro:443"
)
await account.connect_by_server_name(
server_name="YourBroker-Demo",
base_chart_symbol="EURUSD"
)
# Create cancellation event
cancel_event = asyncio.Event()
# Stop after 30 seconds
async def auto_cancel():
await asyncio.sleep(30)
cancel_event.set()
print("\nStopping stream...")
try:
# Start auto-cancel task
cancel_task = asyncio.create_task(auto_cancel())
# Subscribe to multiple symbols
symbols = ["EURUSD", "GBPUSD", "USDJPY"]
async for tick_data in account.on_symbol_tick(
symbols=symbols,
cancellation_event=cancel_event
):
tick = tick_data.symbol_tick
spread_pips = (tick.ask - tick.bid) * 10000 # for 4-digit pairs
print(f"[{tick.time_msc}] {tick.symbol}: "
f"Bid={tick.bid:.5f}, Ask={tick.ask:.5f}, "
f"Spread={spread_pips:.1f} pips")
await cancel_task
finally:
await account.channel.close()
asyncio.run(monitor_multiple_symbols())
3) Track bid-ask spread statistics¶
import asyncio
from collections import defaultdict
from MetaRpcMT5 import MT5Account
async def track_spread_stats():
account = MT5Account(
user=12345,
password="password",
grpc_server="mt5.mrpc.pro:443"
)
await account.connect_by_server_name(
server_name="YourBroker-Demo",
base_chart_symbol="EURUSD"
)
# Statistics storage
spreads = defaultdict(list)
cancel_event = asyncio.Event()
async def stop_after_duration(seconds):
await asyncio.sleep(seconds)
cancel_event.set()
try:
# Stop after 60 seconds
stop_task = asyncio.create_task(stop_after_duration(60))
symbols = ["EURUSD", "GBPUSD"]
async for tick_data in account.on_symbol_tick(
symbols=symbols,
cancellation_event=cancel_event
):
tick = tick_data.symbol_tick
spread = tick.ask - tick.bid
spreads[tick.symbol].append(spread)
await stop_task
# Print statistics
print("\n=== Spread Statistics ===")
for symbol, spread_list in spreads.items():
avg_spread = sum(spread_list) / len(spread_list)
min_spread = min(spread_list)
max_spread = max(spread_list)
print(f"\n{symbol}:")
print(f" Ticks received: {len(spread_list)}")
print(f" Average spread: {avg_spread * 10000:.1f} pips")
print(f" Min spread: {min_spread * 10000:.1f} pips")
print(f" Max spread: {max_spread * 10000:.1f} pips")
finally:
await account.channel.close()
asyncio.run(track_spread_stats())
4) Price alert system¶
import asyncio
from MetaRpcMT5 import MT5Account
async def price_alert_system():
account = MT5Account(
user=12345,
password="password",
grpc_server="mt5.mrpc.pro:443"
)
await account.connect_by_server_name(
server_name="YourBroker-Demo",
base_chart_symbol="EURUSD"
)
# Set price alerts
alerts = {
"EURUSD": {"above": 1.1000, "below": 1.0900},
"GBPUSD": {"above": 1.2700, "below": 1.2500},
}
triggered = set()
try:
async for tick_data in account.on_symbol_tick(
symbols=list(alerts.keys())
):
tick = tick_data.symbol_tick
symbol = tick.symbol
if symbol not in alerts:
continue
# Check above threshold
if tick.bid >= alerts[symbol]["above"]:
alert_key = f"{symbol}_above"
if alert_key not in triggered:
print(f"\n[ALERT] {symbol} bid {tick.bid:.5f} "
f"is ABOVE {alerts[symbol]['above']:.5f}")
triggered.add(alert_key)
# Check below threshold
if tick.bid <= alerts[symbol]["below"]:
alert_key = f"{symbol}_below"
if alert_key not in triggered:
print(f"\n[ALERT] {symbol} bid {tick.bid:.5f} "
f"is BELOW {alerts[symbol]['below']:.5f}")
triggered.add(alert_key)
# Stop if all alerts triggered
if len(triggered) == len(alerts) * 2:
print("\nAll alerts triggered. Stopping...")
break
finally:
await account.channel.close()
asyncio.run(price_alert_system())
5) Real-time tick logger to CSV¶
import asyncio
import csv
from datetime import datetime
from MetaRpcMT5 import MT5Account
async def log_ticks_to_csv():
account = MT5Account(
user=12345,
password="password",
grpc_server="mt5.mrpc.pro:443"
)
await account.connect_by_server_name(
server_name="YourBroker-Demo",
base_chart_symbol="EURUSD"
)
cancel_event = asyncio.Event()
# Stop after 5 minutes
async def auto_stop():
await asyncio.sleep(300)
cancel_event.set()
try:
stop_task = asyncio.create_task(auto_stop())
# Open CSV file
with open('ticks.csv', 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['Timestamp', 'Symbol', 'Bid', 'Ask', 'Last', 'Volume'])
tick_count = 0
async for tick_data in account.on_symbol_tick(
symbols=["EURUSD"],
cancellation_event=cancel_event
):
tick = tick_data.symbol_tick
# Write to CSV
writer.writerow([
datetime.fromtimestamp(tick.time_msc / 1000).isoformat(),
tick.symbol,
tick.bid,
tick.ask,
tick.last,
tick.volume_real
])
tick_count += 1
if tick_count % 100 == 0:
print(f"Logged {tick_count} ticks...")
csvfile.flush() # Flush to disk
await stop_task
print(f"\nTotal ticks logged: {tick_count}")
finally:
await account.channel.close()
asyncio.run(log_ticks_to_csv())
6) Concurrent tick monitoring with tasks¶
import asyncio
from MetaRpcMT5 import MT5Account
async def process_eurusd_ticks(account):
"""Process EURUSD ticks"""
async for tick_data in account.on_symbol_tick(symbols=["EURUSD"]):
tick = tick_data.symbol_tick
print(f"[EUR] {tick.bid:.5f}")
await asyncio.sleep(0.1) # Throttle output
async def process_gbpusd_ticks(account):
"""Process GBPUSD ticks"""
async for tick_data in account.on_symbol_tick(symbols=["GBPUSD"]):
tick = tick_data.symbol_tick
print(f"[GBP] {tick.bid:.5f}")
await asyncio.sleep(0.1) # Throttle output
async def main():
account = MT5Account(
user=12345,
password="password",
grpc_server="mt5.mrpc.pro:443"
)
await account.connect_by_server_name(
server_name="YourBroker-Demo",
base_chart_symbol="EURUSD"
)
try:
# Run multiple streams concurrently
await asyncio.gather(
process_eurusd_ticks(account),
process_gbpusd_ticks(account),
)
except KeyboardInterrupt:
print("\nStopping streams...")
finally:
await account.channel.close()
asyncio.run(main())
📚 See also¶
- SymbolInfoTick - Get current tick snapshot (one-time)
- OnTrade - Stream trade events
- OnPositionProfit - Stream position profit updates