/* eslint-disable complexity */ /* eslint-disable max-len */ import { useEffect, useRef, useState } from 'react'; import MetaApi, { StreamingMetaApiConnectionInstance, SynchronizationListener } from 'metaapi.cloud-sdk'; import { PrintLog, // Logging Sections, Section, // Layout Form, Field // Form } from '../../shared'; interface IStreamQuotesProps { accountId?: string token?: string domain?: string symbol?: string } export function StreamQuotes({ accountId: defaultAccountId, symbol: defaultSymbol, domain: defaultDomain, token: defaultToken } : IStreamQuotesProps) { /* UI control */ const [areResourcesNarrowedDown, setAreResourcesNarrowedDown] = useState(true); const [isConnecting, setIsConnecting] = useState(false); const [isConnected, setIsConnected] = useState(false); /* Logging */ const [resultLog, setResultLog] = useState([]); const [errorLog, setErrorLog] = useState([]); const logErr = (...args: unknown[]) => setErrorLog(logs => { console.log(...args); return [...logs, ...args.map((arg: any) => arg.message || arg)]; }); const log = (...args: unknown[]) => setResultLog(logs => { console.log(...args); return [...logs, ...args]; }); /* Store main variables */ const [accountId, setAccountId] = useState(defaultAccountId || ''); const [token, setToken] = useState(defaultToken || ''); const [domain, setDomain] = useState(defaultDomain || ''); const [symbol, setSymbol] = useState(defaultSymbol || ''); const connectionRef = useRef(); /* Control */ const reset = () => { setIsConnecting(false); setIsConnected(false); setResultLog([]); setErrorLog([]); setAccountId(defaultAccountId || ''); setSymbol(defaultSymbol || ''); setDomain(defaultDomain || ''); setToken(defaultToken ||''); }; const triggerToFetchData = () => { if (isConnected || !token) { return; } setIsConnecting(true); }; useEffect(() => { class QuoteListener extends SynchronizationListener { async onSymbolPriceUpdated(instanceIndex: any, price: any) { if(price.symbol === symbol) { log(symbol + ' price updated', price); } } async onCandlesUpdated(instanceIndex: any, candles: any) { for (const candle of candles) { if (candle.symbol === symbol) { log(symbol + ' candle updated', candle); } } } async onTicksUpdated(instanceIndex: any, ticks: any) { for (const tick of ticks) { if (tick.symbol === symbol) { log(symbol + ' tick updated', tick); } } } async onBooksUpdated(instanceIndex: any, books: any) { for (const book of books) { if (book.symbol === symbol) { log(symbol + ' order book updated', book); } } } async onSubscriptionDowngraded(instanceIndex: any, _symbol: any, updates: any, unsubscriptions: any) { log('Market data subscriptions for ' + _symbol + ' were downgraded by the server due to rate limits'); } } /* Connect to MetaApi */ const connectToMetaApi = async (): Promise => { /* Get instance of MetaApi with your MetaApi token */ const metaApi = new MetaApi(token, { domain }); const areTokenResourcesNarrowedDown = metaApi.tokenManagementApi.areTokenResourcesNarrowedDown(token); setAreResourcesNarrowedDown(areTokenResourcesNarrowedDown as boolean); /* Get MetaTrader account */ const account = await metaApi.metatraderAccountApi.getAccount(accountId); // wait until account is deployed and connected to broker log('Deploying account'); if (account.state !== 'DEPLOYED') { await account.deploy(); } else { log('Account already deployed'); } /* Get connection instance */ log('Waiting for API server to connect to broker (may take couple of minutes)'); if (account.connectionStatus !== 'CONNECTED') { await account.waitConnected(); } const connection = account.getStreamingConnection(); /* Add listener */ const quoteListener = new QuoteListener(); connection.addSynchronizationListener(quoteListener); /* Wait until connection is established */ await connection.connect(); await connection.waitSynchronized(); return connection; }; /* Interaction with metaapi */ const makeRequest = async () => { try { log('Waiting for API server to connect to broker (may take couple of minutes)'); connectionRef.current = await connectToMetaApi(); // Add symbol to MarketWatch if not yet added and subscribe to market data // Please note that currently only G1 and MT4 G2 instances support extended subscription management // Other instances will only stream quotes in response // Market depth streaming is available in MT5 only // ticks streaming is not available for MT4 G1 await connectionRef.current.subscribeToMarketData(symbol, [ {type: 'quotes', intervalInMilliseconds: 5000}, {type: 'candles', timeframe: '1m', intervalInMilliseconds: 10000}, {type: 'ticks'}, {type: 'marketDepth', intervalInMilliseconds: 5000} ]); log('Price after subscribe:', connectionRef.current.terminalState.price(symbol)); log('[' + (new Date().toISOString()) + '] Synchronized successfully, streaming ' + symbol + ' market data now...'); } catch (err) { logErr(err); throw err; } }; const connect = async () => { try { await makeRequest(); log('Start timer fort 60 seconds'); await new Promise(res => setTimeout(res, 1000)); log('60 seconds passed'); } catch (err) { console.log('failed', err); } finally { setIsConnecting(false); } }; const disconnect = () => { if (connectionRef.current) { connectionRef.current.unsubscribeFromMarketData(symbol, [ {type: 'quotes'}, {type: 'candles'}, {type: 'ticks'}, {type: 'marketDepth'} ]).then(() => { log('Stop listening stopout events'); }).catch((err: any) => { logErr(err); }); } }; if (isConnecting && !isConnected) { connect() .then(() => setIsConnected(true)) .then(() => disconnect()) .catch(() => setIsConnected(false)) .finally(() => setIsConnecting(false)); } return disconnect; }, [isConnecting, isConnected]); return (

MetaApi. Stream Quotes

Connect to your account

{!areResourcesNarrowedDown &&

Warning

It seems like you are using a admin API token.

Since the token can be retrieven from the browser or mobile apps by end user this can lead to your application being compromised, unless you understand what are you doing.

Please use Token Management API in your backend application to produce secure tokens which you can then use in web UI or mobile apps.

} {resultLog && resultLog.length > 0 &&

Logs

} {errorLog && errorLog.length > 0 &&

Errors

}
); }