MetaTrader®, MT4® and MT5® are trademarks of MetaQuotes Ltd. This is an independent service and is not affiliated with, authorized by, or endorsed by MetaQuotes.

Signal Providers · 11 min read · 2026-06-09

How to Become a Forex Signal Provider Without Writing a Single Line of MQL5

By MetaTrader API Editorial Team

How to Become a Forex Signal Provider Without Writing a Single Line of MQL5

Become a MetaTrader signal provider with a REST API, no MQL5 needed: connect MT4/MT5, detect trades in real time and broadcast signals with Python.

So you have a profitable trading strategy on MetaTrader. Your EURUSD scalp just hit TP again. Your drawdown has barely touched 4% this month. Friends are already asking: "Can I just copy your trades?"

You've heard of becoming a signal provider on MQL5.com — but that path means passing a verification process, paying listing fees, and being locked inside MetaQuotes' own ecosystem. Worse, if you want to run your own copy trading service, collect subscription fees yourself, or build any kind of product around your signals, MQL5's marketplace won't help you at all.

There is a better way. You can become a fully independent forex signal provider using nothing but a REST API and about 60 lines of Python. No MQL5. No Expert Advisor for you to run. No MetaQuotes approval process. You own the infrastructure, the subscriber list, and the revenue.

This guide shows you exactly how — using real, working API endpoints from MetaTrader API.

What "Signal Provider" Actually Means (Technically)

A signal provider is simply a trader whose order activity — opens, closes, modifications — gets detected the moment it happens and transmitted to a list of subscriber accounts that then replicate the same trade.

The traditional way: write an Expert Advisor in MQL5 that runs inside the MT5 desktop app, monitors the account, and sends data somewhere.

The modern way: connect to your MT5 account from outside MetaTrader via a REST API and WebSocket. Your strategy stays exactly as-is. The API watches your account in real time. When a trade fires, your server broadcasts it to however many subscriber accounts you have.

This is what MetaTrader API was built for.

What You Will Build

By the end of this guide, you will have a working signal provider backend that:

  1. Connects to your master MT5 account through MetaTrader API

  2. Listens for real-time trade events over a WebSocket connection

  3. Detects every new open, partial close and close (new deals are picked up about once per second)

  4. Broadcasts the signal to subscriber accounts (or a Telegram bot, webhook, email — your choice)

There is nothing to install on your side: no EA for you to run, no DLL, no special broker permission.

Prerequisites

Step 1 — Connect Your MT4/MT5 Account via /ConnectEx

MetaTrader API authenticates every request with an API key in the x-api-key header and identifies the trading account by its UUID in the id query parameter. You can connect your account in the dashboard, or from code with /ConnectEx. Called with your management key (Settings → "Create management key", sent as Authorization: Bearer), /ConnectEx connects the account, waits until it is ACTIVE, and returns the account id plus a new apiKey for it. You use both in every later request.

import os, time, requests

API = "https://api.metatraderapi.net"
WS = "wss://api.metatraderapi.net"
MGMT_KEY = os.environ["MTAPI_MGMT_KEY"]   # dashboard → Settings → Create management key

# Your MetaTrader 5 account details
MT5_LOGIN = 62333850              # your MT5 account number
MT5_PASS = "your_mt5_pass"        # the main (trading) password
MT5_SERVER = "MetaQuotes-Demo"    # server name exactly as shown in the MT5 login dialog

AUTH = {"Authorization": f"Bearer {MGMT_KEY}"}

def connect_account():
    r = requests.get(
        f"{API}/ConnectEx",
        headers=AUTH,
        params={
            "user": MT5_LOGIN,
            "password": MT5_PASS,
            "server": MT5_SERVER,
            "platform": "MT5",
            "wait": 60,           # seconds to wait for ACTIVE; keep it at 60 or less (CDN limit)
        },
        timeout=75,
    )
    body = r.json()
    if body.get("status") == "ERROR" or "id" not in body:
        raise RuntimeError(f"connection failed: {body.get('statusReason') or body}")
    account_id, api_key = body["id"], body["apiKey"]   # the apiKey is shown only in this response
    while body.get("status") != "ACTIVE":              # usually ACTIVE within 1–2 minutes
        time.sleep(5)
        body = requests.get(f"{API}/ConnectState", params={"id": account_id},
                            headers=AUTH, timeout=75).json()
        if body.get("status") == "ERROR":
            raise RuntimeError(f"connection failed: {body.get('statusReason')}")
    print(f"Connected. Account id: {account_id}")
    return account_id, api_key

ACCOUNT_ID, API_KEY = connect_account()

api = requests.Session()
api.headers["x-api-key"] = API_KEY

Tip: Save the account id and the API key (as a secret) to a database or .env file and connect only once. The account id is permanent and dropped broker connections are restored automatically; if /ConnectState?id= ever reports DISCONNECTED, call /Reconnect?id=. /ConnectEx puts the broker password in the URL, so from a production backend prefer POST /v1/seats with a JSON body (see the documentation).

For MT4 accounts, pass platform=MT4. The base URL and the endpoints are the same for MT4 and MT5.

Step 2 — No Subscription Call Needed for Trade Events

You do not register for order updates. As soon as you open the account's WebSocket, it pushes every trade action on your master account — every open, every close, every partial close and SL/TP hit — as a TRADE frame, and the full list of open positions as a POSITIONS frame whenever it changes. Quotes are the only thing you subscribe to (see the end of this guide).

Step 3 — Listen on the WebSocket for Real-Time Trade Events

This is where the magic happens. One WebSocket per account, wss://api.metatraderapi.net/v1/stream?id=<account id>, streams all events as JSON in real time. Authentication uses the same API key, passed in the x-api-key header on the WebSocket upgrade request. Every frame has the shape {"type": "...", "data": ...}.

import json
import websocket   # pip install websocket-client

OPEN_POSITIONS = {}   # ticket -> position (symbol, type, volume, sl, tp, profit, ...)

def update_open_positions(positions):
    OPEN_POSITIONS.clear()
    OPEN_POSITIONS.update({p["ticket"]: p for p in positions})

def broadcast_signal(deal):
    print("→ to subscribers:", deal["entry"], deal["symbol"])   # your subscriber logic here

def on_message(ws, message):
    msg = json.loads(message)
    if msg["type"] == "TRADE":
        deal = msg["data"]
        if not deal.get("symbol"):
            return   # defensive: TRADE frames are trade deals, always with a symbol
        # entry: "IN" = opened, "OUT" = closed (fully or partly), "INOUT" = reversed
        print(f"[SIGNAL] {deal['entry']} {deal['type']} {deal['symbol']} | Vol: {deal['volume']} "
              f"| Price: {deal['price']} | Position: {deal['position']}")
        broadcast_signal(deal)   # → your subscriber logic here
    elif msg["type"] == "POSITIONS":
        # full list of open positions, incl. sl and tp: use it to forward SL/TP changes
        update_open_positions(msg["data"])

def on_error(ws, error):
    print(f"WebSocket error: {error}")

def on_close(ws, close_status_code, close_msg):
    print(f"WebSocket closed ({close_status_code} {close_msg}) — reconnecting in 5s...")

def start_websocket(account_id):
    ws = websocket.WebSocketApp(
        f"{WS}/v1/stream?id={account_id}",
        header={"x-api-key": API_KEY},
        on_message=on_message,
        on_error=on_error,
        on_close=on_close,
    )
    ws.run_forever(reconnect=5)   # auto-reconnect 5 seconds after a disconnect

start_websocket(ACCOUNT_ID)

When your master account opens a trade, on_message fires with a frame like this:

{
  "type": "TRADE",
  "data": {
    "deal": 51230011, "order": 182334901, "position": 182334901, "ticket": 51230011,
    "symbol": "EURUSD", "type": "BUY", "entry": "IN", "volume": 0.5, "price": 1.08145,
    "commission": -1.75, "swap": 0.0, "profit": 0.0, "fee": 0.0,
    "magic": 0, "expertId": 0, "comment": "my strategy",
    "time": "2026-10-12T12:15:02Z", "timeUtc": "2026-10-12T09:15:02Z"
  }
}

A TRADE frame carries no stop-loss or take-profit: those are in the sl and tp fields of the matching position (ticket equal to the deal's position) in the POSITIONS frames.

Real-time trading signal distribution architecture diagram using MetaTrader API WebSockets and Python backend

Step 4 — Verify Account Status Before Broadcasting

Before replicating any signal to a subscriber account, it is good practice to verify the subscriber's account is healthy and has sufficient margin. Use /AccountSummary:

def get_account_summary(subscriber_account_id):
    r = api.get(f"{API}/AccountSummary", params={"id": subscriber_account_id}, timeout=75)
    r.raise_for_status()
    return r.json()   # balance, equity, margin, freeMargin, marginLevel, currency, ...

subscriber_account_id = "SUBSCRIBER_ACCOUNT_UUID"   # the subscriber's account id
summary = get_account_summary(subscriber_account_id)
print(f"Subscriber balance: {summary['balance']} | Free Margin: {summary['freeMargin']}")

(One API key can address every trading account of your customer login through ?id=, as long as it is not account-scoped.)

A robust signal service will skip replication if freeMargin is below a threshold, protecting your subscribers from margin calls. This is exactly the kind of risk logic you can build into your own service — something the MQL5 marketplace can never offer you because it runs on their rails, not yours.

Step 5 — Execute the Replicated Trade on the Subscriber Account

Once you've verified the subscriber's account, use /OrderSend to execute the replicated trade. Send a clientOrderId so a retry can never open a second order, and check state: HTTP 200 is not a fill, only state == 10009 is.

def replicate_signal(subscriber_account_id, deal, sl=0, tp=0):
    """Replicate a master opening deal to a subscriber account with proportional sizing."""
    # Example: subscriber uses 25% of master volume
    adjusted_volume = max(0.01, round(deal["volume"] * 0.25, 2))

    r = api.get(f"{API}/OrderSend", params={
        "id": subscriber_account_id,
        "symbol": deal["symbol"],
        "operation": "Buy" if deal["type"] == "BUY" else "Sell",
        "volume": adjusted_volume,
        "stoploss": sl,      # from the master's POSITIONS frame; 0 = none
        "takeprofit": tp,
        "comment": f"copy #{deal['position']}",
        "clientOrderId": f"sig-{deal['deal']}-{subscriber_account_id[:8]}",
    }, timeout=75)
    r.raise_for_status()
    result = r.json()
    if result.get("state") != 10009:
        print(f"Broker refused the copy, retcode {result.get('state')}")
        return None
    print(f"Trade placed on subscriber account: ticket {result['ticket']}")
    return result

Note on MT4: The same /OrderSend call and parameters work for MT4 accounts. A refused MT4 order reports the MT4 error number in state. See the MetaTrader API documentation for the full MT4 vs MT5 comparison.

The Full Architecture at a Glance

Here is the complete signal provider system you now have:

┌─────────────────────────────────────────────────────────┐
│ MASTER ACCOUNT (You)                                    │
│ MT5 Live/Demo Account → MetaTrader API /ConnectEx       │
└──────────────────────┬──────────────────────────────────┘
                       │ WebSocket: wss://.../v1/stream?id=...
                       ▼
┌─────────────────────────────────────────────────────────┐
│ YOUR SIGNAL SERVER (Python)                             │
│ Receives TRADE and POSITIONS frames in real time        │
│ Applies risk filter (margin check, lot sizing)          │
│ Calls /OrderSend on each subscriber account             │
└──────┬────────────────┬───────────────┬─────────────────┘
       ▼                ▼               ▼
 Subscriber A     Subscriber B    Subscriber C
 (0.25x lots)     (0.50x lots)    (1.00x lots)

Each subscriber can have their own lot multiplier, risk cap, or symbol filter. This is your system. You control everything.

What About Getting Paid?

This is where running your own signal service genuinely beats MQL5.

With MQL5 Signals, MetaQuotes sets the rules and keeps a commission on every subscription. And you cannot charge performance fees, PAMM-style profit share, or tiered pricing.

With your own API-based signal service, you can:

All of this is possible because you have programmatic access to /TradeStats, /EquityHistory, and /OpenedOrders for any connected account. You can build a leaderboard, a subscriber portal, or a Telegram bot — anything.

For the dashboard and account automation side of this, see our guide: How Brokers Automate Account Management with MetaTrader API →

Monitoring Your Master Account's Open Positions

Your subscribers want to see what is currently open on your account — before they sign up. Use /OpenedOrders to expose this in real time:

def get_open_positions(account_id):
    r = api.get(f"{API}/OpenedOrders", params={"id": account_id}, timeout=75)
    r.raise_for_status()
    return r.json()   # open positions and pending orders, as order objects

for o in get_open_positions(ACCOUNT_ID):
    print(f"{o['symbol']} | type {o['orderType']} | {o['lots']} lots | P/L: {o['profit']}")

This data powers your public-facing "live performance" widget. Embed it on your website, Telegram channel, or Discord server to attract subscribers.

MQL5 Marketplace vs. Your Own Signal Service: A Real Comparison

Feature MQL5 Marketplace Your Own API Service
Revenue share MetaQuotes keeps a commission 100% to you (minus your payment fees)
Performance fees Not supported Full control
Subscriber data/emails You don't own them Your database
Custom lot sizing per subscriber Fixed Per subscriber
Your own branding/domain MQL5 brand Yours
MQL5 approval required Yes No
EA to install on your side Often No
MT4 + MT5 support Limited Both
Custom subscriber dashboard No Yes

Going Further: Adding WebSocket Quote Streaming

If your signal service also wants to show live prices or market data to subscribers — perhaps to display the current spread before copying a trade — subscribe to quotes on the same /v1/stream WebSocket. Send one message per symbol; QUOTE frames then arrive on every price change (at most one every 200 ms per symbol):

def on_open(ws):
    for symbol in ("EURUSD", "GBPUSD", "XAUUSD"):   # the broker's exact symbol names (/SymbolList)
        ws.send(json.dumps({"action": "subscribe", "symbol": symbol}))

# Pass on_open=on_open to the WebSocketApp from Step 3, and handle QUOTE frames in on_message:
#     if msg["type"] == "QUOTE":
#         q = msg["data"]   # {"symbol": "EURUSD", "bid": 1.08145, "ask": 1.08157, "timeUtc": "...", ...}
#         print(q["symbol"], q["bid"], q["ask"])

Subscriptions belong to one socket: after a reconnect, on_open runs again and subscribes again.

This is how you build a live market data feed into your subscriber dashboard — without paying a separate data vendor. For a deeper dive into real-time streaming and low-latency architecture, see: Low-Latency MetaTrader Infrastructure for Brokers →

If you found this useful, these guides on the MetaTrader API blog take the next steps further:

External resources:

Sign up for MetaTrader API to connect MT4 and MT5 accounts over REST and WebSocket

Build Your Signal Service Today

Everything in this guide runs on MetaTrader API. You can make your first API call in about ten minutes; a newly connected account is usually ACTIVE within 1–2 minutes. A seat costs $14 per month; there is no free trial.

→ Create account at app.metatraderapi.net

→ Read the full API documentation

→ Browse all developer guides on the MetaTrader API Blog

No Expert Advisor for you to run. No MQL5. No MetaQuotes approval process.

Just your strategy, a REST API, and complete control over your signal business.

MetaTrader®, MT4® and MT5® are registered trademarks of MetaQuotes Ltd. MetaTrader API is an independent service and is not affiliated with, authorized by, or endorsed by MetaQuotes.

Frequently asked questions

Do I need MQL5 to become a MetaTrader signal provider?

No. With a REST API like MetaTrader API, you can detect and broadcast your MT4/MT5 trades in real time using Python, Node.js, or any HTTP-capable language — with no Expert Advisor for you to install and no MQL5 code.

How does the MetaTrader API signal provider setup work?

You connect your MT5 account via /ConnectEx (or in the dashboard), then open the MetaTrader API WebSocket at wss://api.metatraderapi.net/v1/stream?id=<account id> with your x-api-key. TRADE and POSITIONS frames arrive without any subscription call (new deals are picked up about once per second). Your server then broadcasts those events to subscribers. Full endpoint details are in the API documentation.

Can I become a signal provider on MT4 and MT5?

Yes. MetaTrader API supports both MetaTrader 4 and MetaTrader 5 with identical endpoints, the same base URL and the same WebSocket. You choose the platform when you connect the account (platform=MT4 or MT5).

How do I get started with MetaTrader API?

Sign up at app.metatraderapi.net and add one seat per MT4 or MT5 account you connect. A seat costs $14 per month (less from the 5th seat); there is no free trial. Your API key is created when you connect the account.

Can I use this with a prop firm funded account?

Yes, as long as your prop firm provides you with the MT5 login credentials and server name. You are connecting to the account as the account holder — the MetaTrader API service acts as a bridge. For prop firm-specific compliance monitoring and rule enforcement, see: Build Prop Firm Rule Enforcement on MetaTrader Accounts →

What if my subscribers use different brokers?

Each subscriber's MT4/MT5 account is connected as its own MetaTrader API seat with its own account id. The account can be at any broker on any server — the API is broker-agnostic. You simply call /OrderSend with each subscriber's account id and the correct symbol name for their broker (e.g., EURUSD vs EURUSD.m).

Is this legal? Am I acting as an unregulated fund manager?

Signal providing — where subscribers manually choose to replicate trades and control their own account — is generally treated differently from fund management across most jurisdictions. However, regulatory rules vary by country. Always consult a financial compliance advisor before charging subscribers for signals. This guide covers the technical implementation only.

Can I add AI to this?

Yes. Because your signal data flows through your own Python server, you can insert any AI layer between the master account event and the subscriber execution. For a complete example of adding OpenAI-based analysis to a MetaTrader pipeline, see: How to Build an AI Forex Trading Bot →

Ready to integrate the MetaTrader API?

REST, WebSocket and gRPC for MT4 and MT5. Pay per connected account.

Create account