MT4 JavaScript TypeScript grpc client from browser (Webpack)

Created with Sketch.

MT4 JavaScript TypeScript grpc client from browser (Webpack)

Table of Contents

Grpc methods browser

Proto file

You need npm be installed

You need npx be installed

npm install -g npx

You need tsc be installed

npm install typescript --save-dev

You need protoc tool be installed

Install protoc plugins

npm install -g protoc-gen-js
npm install -g protoc-gen-grpc-web

You can find ready to run example here

Run example steps:

Step 1. Generate client files. JS and TS files generation by mt5.proto.

protoc proto/*.proto --js_out=import_style=commonjs,binary:./grpc --grpc-web_out=import_style=typescript,mode=grpcwebtext:./grpc

where ./grpc is a output folder
This script generates client's files to the "grpc" folder.

Step 2. Insert your ceredentials in the example

Step 3. Install all dependencies

npm install

Step 4. Compile typescript to js files.

tsc -p .

This script generates client.js file from client.ts file.

Step 5. Bild browser bundle.

npx webpack ./client.js

This script creates main.js file in the dist folder. This file could be consumed by a browser.

Step 6. Create a developer http server. Which would provide bundle files to a browser, by GET request.
For the purpose of prototype demonstration, I would like to recommend using lightweigt developer http server.

npm install --global http-server

Step 7. Finally, you can run a developer server

http-server

Step 8. Check how it works.

Full example:

import {ConnectionClient, MT4Client, StreamsClient, SubscriptionsClient} from "./grpc/proto/Mt4ServiceClientPb";
import {AccountSummaryRequest, ConnectRequest, OnQuoteRequest, SubscribeRequest} from "./grpc/proto/mt4_pb";
import {RpcError} from "grpc-web";

const host : string = ``;
const port : number = 443;
const userId : number = 123;
const password: string = ``;
const currencyPair = `BTCUSD`;

const serverAddress = 'https://mt4grpcweb.mtapi.io:443';
console.log(`Server:${serverAddress}`)
const sessionId = generateUUID();
console.log(`Session id in the headers:${sessionId}`)

const connectionClient = new ConnectionClient(serverAddress);
const mt4Client =  new MT4Client(serverAddress);
const streamClient = new StreamsClient(serverAddress);
const subscriptionClient = new SubscriptionsClient(serverAddress);

ConnectAndDoADemo();

function ConnectAndDoADemo() {
    let connectRequest = new ConnectRequest();
    connectRequest.setHost(host);
    connectRequest.setPort(port);
    connectRequest.setUser(userId);
    connectRequest.setPassword(password);
    connectionClient.connect(connectRequest,
        {'mt4-sticky-session-header' : sessionId},
        (err, response) => {
            if (err) {
                console.error(`RPC ConnectionClient.Connect() error message: ${err.message}`);
            }
            else
            {
                if (response?.getError())
                {
                    console.error(`ConnectionClient.Connect(). Internal server error: ${response?.getError()?.getMessage()}`);
                }
                else
                {
                    console.log(`Successful connected`);
                    let clientConnectionId = response?.getResult();
                    console.log(`Connection client id: ${clientConnectionId}`);
                    if (clientConnectionId)
                    {
                        OnConnectedGetAccountSummary(clientConnectionId);
                        OnConnectedSubscribe(clientConnectionId);
                    }
                }
            }

    });
}

function OnConnectedGetAccountSummary(clientConnectionId: string) {
    const sumReq = new AccountSummaryRequest();
    sumReq.setId(clientConnectionId);
    mt4Client.accountSummary(sumReq, {'mt4-sticky-session-header' : sessionId}, (err, response)  => {
        if (err) {
            console.error(`RPC Mt4Client.accountSummary() error message: ${err.message}`);
        } else {
            if (response?.getError())
                console.error(`Mt4Client.accountSummary(). Internal server error: ${response?.getError()?.getMessage()}`);
            else {
                console.log(`Successful account summary response`);
                let accountSummary = response?.getResult();
                if (accountSummary) {
                    let balance = accountSummary.getBalance();
                    let profit = accountSummary.getProfit();
                    let credit = accountSummary.getCredit();
                    console.log(`Balance: ${balance}, profit ${profit}, credit ${credit}`);
                }
            }
        }
    })
}

function OnConnectedSubscribe(clientConnectionId: string ) {
    const subscriptionRequest = new SubscribeRequest();
    subscriptionRequest.setId(clientConnectionId);
    subscriptionRequest.setSymbol(currencyPair);
    subscriptionClient.subscribe(subscriptionRequest,{"mt4-sticky-session-header": sessionId}, (err:RpcError, reply) => {
        if (err) {
            console.error(`RPC error message: ${err.message}`);
        } else {
            if (reply?.getError())
                console.error(`Internal server error: ${reply?.getError()?.getMessage()}`);
            else {
                console.log(`Successful response`);
                let responseObject = reply?.getResult();
                if (responseObject)
                {
                    console.log(`Subscribed: ${responseObject}`)
                    OnSubscribed(clientConnectionId);
                }
            }
        }
    });
}

function OnSubscribed(clientConnectionId: string) {
    const onQuoteReq = new OnQuoteRequest();
    onQuoteReq.setId(clientConnectionId);
    let serverQuotesStream = streamClient.onQuote(onQuoteReq, {"mt4-sticky-session-header": sessionId});
    serverQuotesStream.on("data", (quoteReply)  => {
        let errorFromServer = quoteReply?.getError();
        if (errorFromServer)
        {
            console.error(`Internal server error: ${errorFromServer?.getMessage()}`);
        }
        else
        {
            console.log(`Successful quote response`);
            let quoteFromServer = quoteReply?.getResult();
            if (quoteFromServer)
            {
                let bid = quoteFromServer.getBid();
                let ask = quoteFromServer.getAsk();
                let symbol = quoteFromServer.getSymbol();
                let time = quoteFromServer.getTime();
                let low = quoteFromServer.getLow();
                console.log(`Bid ${bid}. Ask ${ask}. Symbol ${symbol}. Time ${time}. Low ${low}`)
            }
        }
    });
    serverQuotesStream.on('status', (status): void => {
        console.log(`Status received`);
        console.log(`Status code: ${status.code}`);
        console.log(`Status details: ${status.details}`);
        console.log(`Status metadata: ${status.metadata}`);
    });
    serverQuotesStream.on("error", err => {
        console.error(`Stream error code: ${err.code}. Message: ${err.message}`);
    })
    serverQuotesStream.on("end", function () {
        console.log(`End received`);
    })
}

function generateUUID() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        let r = Math.random() * 16 | 0,
            v = c === 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

Leave a Reply

Your email address will not be published. Required fields are marked *