MT5 JavaScript TypeScript grpc client from browser (Webpack)

MT5 JavaScript TypeScript grpc client from browser (Webpack)

Grpc methods browser

MT5 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

You can use any presented link.

The example:

import {ConnectionClient, MT5Client, StreamsClient, SubscriptionsClient} from './grpc/proto/Mt5ServiceClientPb';
import {
    AccountSummaryRequest,
    ConnectReply,
    ConnectRequest,
    OnQuoteRequest,
    SubscribeRequest
} from "./grpc/proto/mt5_pb";
import {RpcError} from "grpc-web";

const currencyPair = `BTCUSD`;
const serverAddress = 'https://mt5grpcweb.mtapi.io:443';
console.log(`Server:${serverAddress}`)
const sessionId = generateUUID();

const mt5Client = new MT5Client(serverAddress);
const connectionClient = new ConnectionClient(serverAddress);
const subscriptionClient = new SubscriptionsClient(serverAddress);
const streamClient = new StreamsClient(serverAddress);

ConnectToTheServer();

function ConnectToTheServer() {
    const connectRequest = new ConnectRequest()
        .setHost("") // TODO
        .setUser(1) // TODO
        .setPort(443) // TODO
        .setPassword(""); // TODO

    connectionClient.connect(connectRequest, { "mt5-sticky-session-header" : sessionId}, (err:RpcError, value: ConnectReply) => {
        if (err) {
            console.error(`RPC  error message: ${err.message}`);
        } else {
            if (value?.getError())
                console.error(`Internal server error: ${value?.getError()?.getMessage()}`);
            else {
                console.log(`Successful response`);
                if (value?.getResult()) {
                    console.log(`Connection id: ${value?.getResult()}`);
                    let clientConnectionId = value?.getResult();
                    if (clientConnectionId)
                    {
                        OnConnectedGetAccountSummary(clientConnectionId);
                        OnConnectedSubscribe(clientConnectionId);
                    }
                }
            }
        }
    })
}

function OnConnectedGetAccountSummary(connectionId: string ) {
    const sumReq = new AccountSummaryRequest();
    sumReq.setId(connectionId);
    mt5Client.accountSummary(sumReq,{"mt5-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 accountSummary = reply?.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,{"mt5-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 stream = streamClient.onQuote(onQuoteReq, {"mt5-sticky-session-header": sessionId});
    stream.on('data', function (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 last = quoteFromServer.getLast();
                let symbol = quoteFromServer.getSymbol();
                let time = quoteFromServer.getTime();
                let volume = quoteFromServer.getVolume();

                console.log(`Bid ${bid}. Ask ${ask}. Last ${last}. Symbol ${symbol}. Time ${time}. Volume ${volume}`)
            }
        }
    });
    stream.on('status', function (status) : void {
        console.log(`Status received`);
        console.log(`Status code: ${status.code}`);
        console.log(`Status details: ${status.details}`);
        console.log(`Status metadata: ${status.metadata}`);
    });
    stream.on("error", err => {
        console.error(`Stream error code: ${err.code}. Message: ${err.message}`);
    })
    stream.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 *