MT4 JavaScript TypeScript grpc client from browser (Webpack)
npm install -g npx
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);
});
}