@presspage/metatrader-bridge
Version:
A Metatrader Bridge API Server
1,403 lines (1,297 loc) • 154 kB
JavaScript
"user strict"
var md5 = require("nodejs-md5");
var fs = require("fs");
var cors = require("cors");
var express = require("express");
var killable = require('killable');
var talib = require('ta-lib');
let MAX_SESSIONS=50;
/**
* ERROR_CODES An enumeration of available error codes
*/
const ERROR_CODES = {
RET_OK: 0,
RET_OK_NONE: 1,
RET_ERROR: 2,
RET_INVALID_DATA: 3,
RET_TECH_PROBLEM: 4,
RET_ACCOUNT_DISABLED: 5,
RET_BAD_ACCOUNT_INFO: 6,
RET_TIMEOUT: 7,
RET_BAD_PRICES: 8,
RET_MARKET_CLOSED: 9,
RET_TRADE_DISABLE: 10,
RET_NO_MONEY: 11,
RET_PRICE_CHANGED: 12,
RET_OFFQUOTES: 13,
RET_BROKER_BUSY: 14,
RET_OLD_VERSION: 15,
RET_MULTI_CONNECT: 16,
RET_NO_CONNECT: 17,
RET_NOT_ENOUGH_RIGHTS: 18,
RET_BAD_STOPS: 19,
RET_SKIPPED: 20,
RET_TOO_FREQUENT: 21,
RET_INVALID_VOLUME: 22,
RET_INVALID_HANDLE: 23,
RET_INSTANTEXECUTION: 24
};
/**
* COMMANDS An enumeration of accepted commands
*/
const COMMANDS = {
OP_BUY: 0,
OP_SELL: 1,
OP_BUY_LIMIT: 2,
OP_SELL_LIMIT: 3,
OP_BUY_STOP: 4,
OP_SELL_STOP: 5,
OP_BALANCE: 6,
OP_CREDIT: 7,
OP_CLOSEPENDING: 8,
OP_CLOSEALL: 9,
OP_UNKNOWN: 10
};
/**
* RateInfo A class object defining currency rates
*/
class RateInfo {
constructor() {
this.ctm = 0;
this.open = 0;
this.low = 0;
this.high = 0;
this.close = 0;
this.vol = 0;
}
};
/**
* SESSION A class object containing basic trade session information
*/
class SESSION {
constructor() {
this.acctnum = 0;
this.handle = 0;
this.symbol = "";
this.symbol1 = "";
this.symbol2 = "";
this.symbol3 = "";
this.index = 0;
this.magic = 0;
this.order_status = "";
}
};
/**
* ACCOUNT A class object for account information
*/
class ACCOUNT {
constructor() {
this.id = 0;
this.number = 0;
this.balance = 0;
this.equity = 0;
this.leverage = 0;
}
};
/**
* CCYPAIRS A class object representing a single currency pair
*/
class CCYPAIRS
{
constructor() {
this.id = 0;
this.symbol = "";
this.handle = 0;
this.period = 0;
this.number = 0;
}
};
/**
* HISTORY A class object for holding currency rate history
*/
class HISTORY
{
constructor() {
this.id = 0;
this.symbol = "";
this.open = 0;
this.high = 0;
this.low = 0;
this.close = 0;
this.volume = 0;
this.ctm = 0;
this.handle = 0;
}
};
/**
* HISTORYMAP A class object for mapping currency rate history
*/
class HISTORYMAP
{
constructor(){
this.mapfile = null;
this.name = "";
this.handle = 0;
this.size = 0;
}
};
/**
* MARGIN A class object representing account margin requirements and information
*/
class MARGIN
{
constructor(){
this.id = 0;
this.symbol = "";
this.handle = 0;
this.margininit = 0;
this.marginmaintenance = 0;
this.marginhead = 0;
this.marginrequired = 0;
this.margincalcmode = 0;
}
};
/**
* MARKETINFO A class object representing the market information for a currency pair
*/
class MARKETINFO
{
constructor(){
this.id = 0;
this.number = 0;
this.symbol = "";
this.points = 0;
this.digits = 0;
this.spread = 0;
this.stoplevel = 0;
this.lotsize = 0;
this.tickvalue = 0;
this.ticksize = 0;
this.swaplong = 0;
this.swapshort = 0;
this.profitcalcmode = 0;
this.freezelevel = 0;
this.leverage = 0;
}
};
/**
* RESPONSES A class object representing a common response
*/
class RESPONSES
{
constructor(){
this.id = 0;
this.symbol = "";
this.handle = 0;
this.message = "";
this.errorcode = 0;
this.respcode = 0;
this.read = 0;
this.timestamp = "";
this.tradeid = 0;
}
};
/**
* TICKS A class object representing a single rate price point
*/
class TICKS
{
constructor(){
this.id = 0;
this.symbol = "";
this.margin = 0;
this.freemargin = 0;
this.tickdate = "";
this.ask = 0;
this.bid = 0;
this.equity = 0;
}
};
/**
* TRADECOMMANDS A clas object representing the trade commands
*/
class TRADECOMMANDS
{
constructor() {
this.id = 0;
this.symbol = "";
this.symbol1 = "";
this.symbol2 = "";
this.symbol3 = "";
this.cmd = 0;
this.cmd1 = 0;
this.cmd2 = 0;
this.cmd3 = 0;
this.lots = 0;
this.lots2 = 0;
this.lots3 = 0;
this.price = 0;
this.slippage = 0;
this.comment = "";
this.color = 0;
this.timestamp = "";
this.completed = 0;
this.handle = 0;
this.magic = 0;
this.expiration = "";
this.stoploss = 0;
this.takeprofit = 0;
this.volume = 0;
this.ticket = 0;
}
};
// Shared among threads
class SharedMemory {
static index = 0;
static session_count = 0;
static queue_position = Array(MAX_SESSIONS);
static session = Array(MAX_SESSIONS); // SESSION
static history = Array(MAX_SESSIONS); // RateInfo
static ccy1history = Array(MAX_SESSIONS); // RateInfo
static ccy2history = Array(MAX_SESSIONS); // RateInfo
static ccy3history = Array(MAX_SESSIONS); // RateInfo
static bid = Array(MAX_SESSIONS);
static ask = Array(MAX_SESSIONS);
static close = Array(MAX_SESSIONS);
static volume = Array(MAX_SESSIONS);
static swap_rate_long = Array(MAX_SESSIONS);
static swap_rate_short = Array(MAX_SESSIONS);
static account = Array(MAX_SESSIONS); // ACCOUNT
static ccypairs = Array(MAX_SESSIONS); // CCYPAIRS
static marketinfo = Array(MAX_SESSIONS); // MARKETINFO
static margininfo = Array(MAX_SESSIONS); // MARGIN
static trade_commands = Array(MAX_SESSIONS); // TRADECOMMANDS
static response = Array(MAX_SESSIONS); // RESPONSES
static ticks = Array(100); // TICKS
static hHistory = Array(MAX_SESSIONS); // HANDLE
static history_count = Array(MAX_SESSIONS);
static all_currencies = Array(MAX_SESSIONS);
}
Array.matrix = function(numrows, numcols, initial) {
var arr = [];
for (var i = 0; i < numrows; ++i) {
var columns = [];
for (var j = 0; j < numcols; ++j) {
columns[j] = initial;
}
arr[i] = columns;
}
return arr;
}
function Write(filename, data, callback) {
fs.appendFile(filename, data, callback);
}
function Read(filename, callback) {
fs.readFile(filename,'r',callback);
}
function FindExistingSession(acctnum,handle,symbol) {
let found = -1;
for (let n=0; n<MAX_SESSIONS; n++) {
if (SharedMemory.session[n].acctnum == Number(acctnum) &&
SharedMemory.session[n].handle == Number(handle) &&
SharedMemory.session[n].symbol == symbol) {
found = n + 1;
return found;
}
}
return found;
}
var app = null;
var server = null;
class MetatraderBridge {
constructor(max_sessions=50,host="",port=3000) {
MAX_SESSIONS = max_sessions;
// Initialze session variable
for(let i=0; i<MAX_SESSIONS; i++) {
SharedMemory.account[i] = new ACCOUNT();
SharedMemory.ccypairs[i] = new CCYPAIRS();
SharedMemory.marketinfo[i] = new MARKETINFO();
SharedMemory.margininfo[i] = new MARGIN();
SharedMemory.response[i] = new RESPONSES();
SharedMemory.history[i] = new RateInfo();
SharedMemory.ccy1history[i] = new RateInfo();
SharedMemory.ccy2history[i] = new RateInfo();
SharedMemory.ccy3history[i] = new RateInfo();
SharedMemory.session[i] = new SESSION();
SharedMemory.trade_commands[i] = new TRADECOMMANDS();
}
for (let i=0; i<100; i++) {
SharedMemory.ticks[i] = new TICKS();
}
app = express();
app.use(express.json());
app.use(express.urlencoded({
extended: true
}));
app.use(express.json());
app.use(cors()); // enable cors
app.use(function (err, req, res, next) {
res.json({success: false, data: err.stack});
});
/**
* @api {get} / Displays the available routes
* @apiName GetRoutes
* @apiGroup Utility
* @apiParam nothing
*
* @apiSuccess {Object} list of routes
* @apiSuccessExample {json} Success-Response:
* [
* "get -> /",
* "get -> /about",
* "get -> /md5/:password",
* "purge -> /Shutdown",
* "get -> /ResetAll",
* "get -> /GetMaximumSessions",
* "get -> /FindExistingSession/:acctnum,:symbol,:handle",
* "put -> /Initialize/:acctnum,:handle,:symbol,:symbol1,:symbol2,:symbol3",
* "put -> /InitializeCurrency1/:acctnum,:handle,:symbol",
* "put -> /InitializeCurrency2/:acctnum,:handle,:symbol,:magic",
* "put -> /InitializeCurrency3/:acctnum,:handle,:symbol,:magic",
* "delete -> /DeInitialize/:index",
* "get -> /GetSessionCount",
* "get -> /GetSession/:index",
* "get -> /GetAllSessions",
* "get -> /GetAllAccounts",
* "get -> /GetAllCurrencyPairs",
* "get -> /GetAllMarketInfo",
* "get -> /GetAllMarginInfo",
* "get -> /GetAllResponses",
* "get -> /GetAllHistory",
* "get -> /GetAllCurrency1History",
* "get -> /GetAllCurrency2History",
* "get -> /GetAllCurrency3History",
* "get -> /GetAllTradeCommands",
* "get -> /GetAllPrices",
* "get -> /GetDllVersion",
* "get -> /GetVersion",
* "put -> /SetBidAsk/:session,:bid,:ask,:close,:volume",
* "get -> /GetBid/:session",
* "put -> /SetBid/:session,:quote",
* "put -> /SetBidCurrencyOne/:session,:currency,:quote",
* "put -> /SetBidCurrencyTwo/:session,:currency,:quote",
* "put -> /SetBidCurrencyThree/:session,:currency,:quote",
* "get -> /GetAsk/:session",
* "put -> /SetAsk/:session,:quote",
* "get -> /GetVolume/:session",
* "get -> /GetClose/:session",
* "put -> /SaveAccountInfo/:session,:number,:balance,:equity,:leverage",
* "get -> /GetAccountInfo/:session",
* "get -> /GetAccountNumber/:session",
* "get -> /GetAccountBalance/:session",
* "get -> /GetAccountEquity/:session",
* "get -> /GetAccountLeverage/:session",
* "put -> /SaveCurrencySessionInfo/:session,:symbol,:handle,:period,:number",
* "get -> /GetSessionCurrency/:session",
* "get -> /GetSessionCurrency1/:session",
* "get -> /GetSessionCurrency2/:session",
* "get -> /GetSessionCurrency3/:session",
* "get -> /GetSessionHandle/:session",
* "get -> /GetSessionPeriod/:session",
* "delete -> /DecrementQueuePosition/:session",
* "put -> /SaveMarketInfo/:session,:number,:leverage,:symbol,:points,:digits,:spread,:stoplevel",
* "get -> /GetDigits/:session",
* "get -> /GetSpread/:session",
* "get -> /GetStoplevel/:session",
* "get -> /GetPoints/:session",
* "put -> /SaveMarginInfo/:session,:symbol,:handle,:margininit,:marginmaintenance,:marginhedged,:marginrequired,:margincalcmode",
* "get -> /GetMarginInit/:session",
* "get -> /GetMarginMaintenance/:session",
* "get -> /GetMarginHedged/:session",
* "get -> /GetMarginRequired/:session",
* "get -> /GetMarginCalcMode/:session",
* "get -> /GetTradeOpCommands/:session",
* "get -> /GetTradeOpCommand/:session",
* "get -> /GetTradeOpCommand1/:session",
* "get -> /GetTradeOpCommand2/:session",
* "get -> /GetTradeOpCommand3/:session",
* "get -> /GetAllCurrencies/:session",
* "post -> /SaveAllCurrencies",
* "put -> /SaveSingleHistory/:session,:index,:time,:open,:close,:high,:low,:volume",
* "post -> /SaveHistory",
* "put -> /SaveHistory/:session,:index,:time,:open,:high,:low,:close,:volume",
* "post -> /SaveHistoryCcy1",
* "post -> /SaveHistoryCcy2",
* "post -> /SaveHistoryCcy3",
* "put -> /SaveTick/:session",
* "get -> /GetTick/:session",
* "get -> /RetrieveHistoryBufferSize/:session",
* "get -> /RetrieveHistorical/:session",
* "get -> /RetrieveHistorical/:session,:index",
* "get -> /RetrieveHistoricalOpen/:session,:index",
* "get -> /RetrieveHistoricalHigh/:session,:index",
* "get -> /RetrieveHistoricalLow/:session,:index",
* "get -> /RetrieveHistoricalClose/:session,:index",
* "get -> /RetrieveHistoricalVolume/:session,:index",
* "get -> /RetrieveHistoricalTime/:session,:index",
* "get -> /RetrieveHistoricalOpen2/:pair,:session,:index",
* "get -> /RetrieveHistoricalHigh2/:pair,:session,:index",
* "get -> /RetrieveHistoricalLow2/:pair,:session,:index",
* "get -> /RetrieveHistoricalClose2/:pair,:session,:index",
* "get -> /RetrieveHistoricalVolume2/:pair,:session,:index",
* "get -> /RetrieveHistoricalTime2/:pair,:session,:index",
* "put -> /SendResponse/:session,:errorcode,:respcode,:message,:ticket",
* "get -> /GetResponseErrorCode/:session",
* "get -> /GetResponseCode/:session",
* "get -> /GetResponseMessage/:session",
* "get -> /GetTicketNumber/:session",
* "get -> /SendTradeCommands/:session,:cmd,:symbol,:lots,:price,:stoploss,:profit",
* "post -> /SendTradeCommands",
* "get -> /SendTradeCommands2/:session,:cmd,:symbol1,:lots,:cmd2,:symbol2,:lots2,:cmd3,:symbol3,:lots3",
* "post -> /SendTradeCommands2",
* "get -> /SetOrderStatus/:session,:status",
* "put -> /SetOrderStatus",
* "get -> /GetOrderStatus/:session",
* "get -> /GetTradePrice/:session",
* "get -> /GetTradeLots/:session",
* "get -> /GetTradeLots2/:session",
* "get -> /GetTradeLots3/:session",
* "get -> /GetTradeStoploss/:session",
* "get -> /GetTradeTakeprofit/:session",
* "delete -> /ResetTradeCommand/:session",
* "get -> /GetTradeCurrency/:session",
* "get -> /GetTradeCurrency2/:session",
* "get -> /GetTradeCurrency3/:session",
* "get -> /GetSwapRateLong/:session",
* "get -> /GetSwapRateShort/:session",
* "get -> /SetSwapRateLong/:session,:rate",
* "get -> /SetSwapRateShort/:session,:rate",
* "get -> /PipSize/:session",
* "get -> /MovingAverages/:session",
* "get -> /TechnicalIndicators/:session,:period"
* ]
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/'
*/
app.get("/", function(req, res, next){
try {
const routes = [];
app._router.stack.forEach(middleware => {
if (middleware.route) {
routes.push(`${Object.keys(middleware.route.methods)} -> ${middleware.route.path}`);
}
});
res.json(routes);
} catch(error) {
next(error);
}
});
// Displays PACKAGE.JSON information
/**
* @api {get} /about Displays PACKAGE.JSON information with Cluster worker and CPU count
* @apiName About
* @apiGroup Utility
*
* @apiParam nothing
*
* @apiSuccess {Object} package json object
* @apiSuccessExample {json} Success-Response:
* {
* "name": "@presspage/metatrader-bridge",
* "version": "1.0.0",
* "description": "A Metatrader Bridge API Server",
* "homepage": "https://github.com/pingleware/metatrader-bridge",
* "bugs": {
* "url": "https://github.com/pingleware/metatrader-bridge/issues",
* "email": "presspage.entertainment@gmail.com"
* },
* "main": "index.js",
* "scripts": {
* "test": "echo \"Error: no test specified\" && exit 1",
* "doc": "apidoc -f index.js -e ./node_modules -o ./doc/"
* },
* "keywords": [
* "metatrader",
* "forex",
* "algorithmic trading"
* ],
* "repository": {
* "url": "https://github.com/pingleware/metratrader-bridge.git",
* "type": "git"
* },
* "author": {
* "name": "PressPage Entertainment Inc DBA PINGLEWARE",
* "email": "presspage.entertainment@gmail.com",
* "url": "https://pingleware.work"
* },
* "maintainers": [
* {
* "name": "Patrick Ingle",
* "email": "me@patruckingle.info",
* "url": "https://patrickingle.info"
* }
* ],
* "license": "CC-BY-4.0",
* "private": false,
* "engines": {
* "node": ">=6.0.0"
* },
* "engineStrict": true,
* "dependencies": {
* "body-parser": "^1.19.0",
* "cors": "^2.8.5",
* "express": "^4.17.1",
* "killable": "^1.0.1",
* "nodejs-md5": "^1.1.0",
* "ta-lib": "^0.11.0"
* }
* }
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/about'
*
*/
app.get("/about", function(req, res, next){
try {
var pjson = require('./package.json');
res.json(pjson);
} catch(error) {
next(error);
}
});
// Generates a MD5 hash from a plain text password, hash is saved to SETTINGS.JSON
/**
* @api {get} /md5/:password Generates a MD5 hash from a plain text password, hash is saved to SETTINGS.JSON
* @apiName Password
* @apiGroup Utility
*
* @apiParam {string} password A plain text password to be hashed
*
* @apiSuccess {Number} session The session
* @apiSuccessExample {string} Success-Response:
* "5f4dcc3b5aa765d61d8327deb882cf99"
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/md5/password'
*
*/
app.get('/md5/:password', function(req, res, next){
try {
md5.string.quiet(req.params.password, function (err, md5) {
if (err) {
res.json(err);
}
else {
res.json(md5);
}
});
} catch(error) {
next(error);
}
});
// Shutdowns the server with password authentication
/**
* @api {all} /shutdown Shutdowns the server
* @apiName Shutdown
* @apiGroup Utility
*
* @apiParam {string} password A plain text password to be hashed
*
* @apiSuccess {Number} session The session
* @apiSuccessExample {string} Success-Response:
* "Server is going down NOW!"
*
* @apiExample {curl} Example usage:
* curl --location --request PURGE 'http://localhost:3000/shutdown'
*
*/
app.all('/Shutdown', function (req, res, next) {
try {
res.json('Server is going down NOW!');
server.kill(function () {
//the server is down when this is called. That won't take long.
});
} catch(error) {
next(error);
}
});
/**
* @api {get} /ResetAll Reinitializes the save session data to zero
* @apiName ResetAll
* @apiGroup Utility
*
* @apiSuccess {Number} session The session
* @apiSuccessExample {number} Success-Response:
* 1
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/ResetAll'
*
*/
app.delete("/ResetAll", function(req, res, next){
try {
for(let i=0; i<MAX_SESSIONS; i++) {
SharedMemory.account[i] = new ACCOUNT();
SharedMemory.ccypairs[i] = new CCYPAIRS();
SharedMemory.marketinfo[i] = new MARKETINFO();
SharedMemory.margininfo[i] = new MARGIN();
SharedMemory.response[i] = new RESPONSES();
SharedMemory.history[i] = new RateInfo();
SharedMemory.ccy1history[i] = new RateInfo();
SharedMemory.ccy2history[i] = new RateInfo();
SharedMemory.ccy3history[i] = new RateInfo();
SharedMemory.session[i] = new SESSION();
SharedMemory.trade_commands[i] = new TRADECOMMANDS();
}
for (let i=0; i<100; i++) {
SharedMemory.ticks[i] = new TICKS();
}
SharedMemory.session_count = 0;
res.json(SharedMemory);
} catch(error) {
next(error);
}
});
/**
* @api {get} /GetMaximumSessions Obtains the maximum sessions allowed
* @apiName GetMaximumSessions
* @apiGroup Session
*
* @apiSuccess {Number} session The session
* @apiSuccessExample {number} Success-Response:
* 50
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/GetMaximumSessions'
*
*/
app.get("/GetMaximumSessions", function(req, res, next){
res.json(MAX_SESSIONS);
});
/**
* @api {get} /FindExistingSession/:acctnum,:handle,:symbol Locates an existing session by account number, window handle and symbol
* @apiName FindExistingSession
* @apiGroup Session
*
* @apiParam {string} acctnum The account number
* @apiParam {string} handle The window handle that the ForexGeneral.ex4 is attached
* @apiParam {string} symbol The currency pair of the above window handle
*
* @apiSuccess {Number} session The session
* 1
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/FindExistingSession/1551102,EURUSDi,263854'
*/
app.get("/FindExistingSession/:acctnum,:symbol,:handle", function(req, res,next){
try {
res.json(FindExistingSession(req.params.acctnum, req.params.handle, req.params.symbol));
} catch(error) {
next(error);
}
});
function Initialize(acctnum, handle, symbol) {
var session_number = -1;
for (let i=0;i<MAX_SESSIONS;i++) {
if (SharedMemory.session[i].index != 0 && SharedMemory.session[i].acctnum == acctnum && SharedMemory.session[i].symbol == symbol) {
session_number = i;
SharedMemory.session[i].acctnum = acctnum;
SharedMemory.session[i].handle = handle;
SharedMemory.session[i].symbol = symbol;
SharedMemory.session[i].symbol1 = "";
SharedMemory.session[i].symbol2 = "";
SharedMemory.session[i].symbol3 = "";
SharedMemory.trade_commands[i].cmd = COMMANDS.OP_UNKNOWN;
SharedMemory.queue_position[i] = 0;
return SharedMemory.session[i].index;
break;
} else if (SharedMemory.session[i].index == 0) {
SharedMemory.session_count++;
SharedMemory.session[i].index = SharedMemory.session_count;
SharedMemory.session[i].acctnum = acctnum;
SharedMemory.session[i].handle = handle;
SharedMemory.session[i].symbol = symbol;
SharedMemory.session[i].symbol1 = "";
SharedMemory.session[i].symbol2 = "";
SharedMemory.session[i].symbol3 = "";
SharedMemory.trade_commands[i].cmd = COMMANDS.OP_UNKNOWN;
SharedMemory.queue_position[i] = 0;
return SharedMemory.session_count;
}
}
return (session_number);
}
/**
* @api {post} Initialize
* @apiName Initialize
* @apiGroup Session
*
* @apiParam {string} acctnum The account number
* @apiParam {string} handle The window handle that the ForexGeneral.ex4 is attached
* @apiParam {string} symbol The currency pair of the above window handle
*
* @apiSuccess {Number} session The session
* 1
*
* @apiExample {curl} Example usage:
* curl --location --request PUT 'http://localhost:3000/Initialize/1551102,132852,EURUSD,AUDJPY,CADJPY,AUDCAD' \
* --header 'Content-Type: application/x-www-form-urlencoded'
*/
app.post("/Initialize", function(req, res, next){
try {
res.json(Initialize(req.body.acctnum, req.body.handle, req.body.symbol));
} catch(error) {
next(error);
}
});
/**
* @api {get} /Initialize/:acctnum,:handle,:symbol Initializes a session
* @apiName Initialize
* @apiGroup Session
*
* @apiParam {string} acctnum The account number
* @apiParam {string} handle The window handle that the ForexGeneral.ex4 is attached
* @apiParam {string} symbol The currency pair of the above window handle
*
* @apiSuccess {Number} session The session
* 1
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/Initialize/1551102,132852,EURUSD' \
* --header 'Content-Type: application/x-www-form-urlencoded'
*/
app.get("/Initialize/:acctnum,:handle,:symbol", function(req, res, next){
try {
res.json(Initialize(req.params.acctnum, req.params.handle, req.params.symbol))
} catch(error) {
next(error);
}
});
/**
* @api {put} /InitializeCurrency1/:acctnum,:handle,:symbol,:magic Initializes a session for one of currency pair within the triad
* @apiName InitializeCurrency1
* @apiGroup Session
*
* @apiParam {string} acctnum The account number
* @apiParam {string} handle The window handle that the ForexGeneral.ex4 is attached
* @apiParam {string} symbol The currency pair of the above window handle
*
* @apiSuccess {Number} session The session
* 2
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/InitializeCurrency1/1551102,263854,USDJPY,000000001'
*
*/
app.put("/InitializeCurrency1/:acctnum,:handle,:symbol.:magic", function(req, res, next){
try {
for (let i=0;i<MAX_SESSIONS;i++) {
if (SharedMemory.session[i].index == 0) {
SharedMemory.session[i].index = i+1;
SharedMemory.session[i].acctnum = req.params.acctnum;
SharedMemory.session[i].handle = req.params.handle;
SharedMemory.session[i].symbol1 = req.params.symbol;
SharedMemory.session_count++;
SharedMemory.trade_commands[i].cmd1 = -1;
SharedMemory.trade_commands[i].cmd2 = -1;
SharedMemory.trade_commands[i].cmd3 = -1;
SharedMemory.queue_position[i] = 0;
SharedMemory.session[i].magic = req.params.magic;
res.json(i+1);
}
}
} catch(error) {
next(error);
}
});
/**
* const int acctnum,const int handle,const char *symbol,const int magic
*/
/**
* @api {put} /InitializeCurrency2/:acctnum,:handle,:symbol,:magic Initializes a session for one of currency pair within the triad
* @apiName InitializeCurrency2
* @apiGroup Session
*
* @apiParam {string} acctnum The account number
* @apiParam {string} handle The window handle that the ForexGeneral.ex4 is attached
* @apiParam {string} symbol The currency pair of the above window handle
* @apiParam {string} magic A unique identifier
*
* @apiSuccess {Number} session The session
* 2
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/InitializeCurrency2/1551102,263854,USDJPY,000000002'
*
*/
app.put("/InitializeCurrency2/:acctnum,:handle,:symbol,:magic", function(req, res, next){
try {
let result = -1;
if (!req.params.magic) {
res.json(result);
} else {
for (let i=0;i<MAX_SESSIONS;i++) {
if (SharedMemory.session[i].magic == req.params.magic) {
SharedMemory.session[i].symbol2 = req.params.symbol;
result = i+1;
}
}
res.json(result);
}
} catch(error) {
next(error);
}
});
/**
* const int acctnum,const int handle,const char *symbol,const int magic
*/
/**
* @api {put} /InitializeCurrency3/:acctnum,:handle,:symbol,:magic Initializes a session for one of currency pair within the triad
* @apiName InitializeCurrency3
* @apiGroup Session
*
* @apiParam {string} acctnum The account number
* @apiParam {string} handle The window handle that the ForexGeneral.ex4 is attached
* @apiParam {string} symbol The currency pair of the above window handle
* @apiParam {string} magic A unique identifier
*
* @apiSuccess {Number} session The session
* 2
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/InitializeCurrency3/1551102,263854,USDJPY,000000002'
*
*/
app.put("/InitializeCurrency3/:acctnum,:handle,:symbol,:magic", function(req, res, next){
try {
let result = -1;
if (!req.params.magic) {
res.json(result);
} else {
for (let i=0;i<MAX_SESSIONS;i++) {
if (SharedMemory.session[i].magic == req.params.magic) {
SharedMemory.session[i].symbol3 = req.params.symbol;
result = i+1;
}
}
res.json(result);
}
} catch(error) {
next(error);
}
});
/**
* @api {get} /DeInitialize/:index Removes the following session, deinitializes
* @apiName DeInitialize
* @apiGroup Session
*
* @apiParam {number} index The session number
*
* @apiSuccess {Number} session The session
* { 0 }
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/DeInitialize/1'
*
*/
app.get("/DeInitialize/:index", function(req, res, next){
try {
if (req.params.index > MAX_SESSIONS || req.params.index > SharedMemory.session_count || req.params.index < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
SharedMemory.session[req.params.index-1].index = 0;
SharedMemory.session[req.params.index-1].acctnum = 0;
SharedMemory.session[req.params.index-1].handle = 0;
SharedMemory.session[req.params.index-1].symbol = "0";
SharedMemory.trade_commands[req.params.index-1].cmd = COMMANDS.OP_UNKNOWN;
SharedMemory.queue_position[req.params.index-1] = 0;
if (SharedMemory.session_count > 0) {
SharedMemory.session_count--;
}
res.json(ERROR_CODES.RET_OK);
}
} catch(error) {
next(error);
}
});
/**
* @api {get} /GetSessionCount Obtains the total sessions created
* @apiName GetSessionCount
* @apiGroup Session
*
* @apiSuccess {Number} the number of active sessions
* { 0 }
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/GetSessionCount'
*/
app.get("/GetSessionCount", function(req, res, next){
res.json(SharedMemory.session_count);
});
/**
* @api {get} /GetSession/:index Retrieves a single session
* @apiName GetSession
* @apiGroup Session
*
* @apiParam {number} index The session number
*
* @apiSuccess {Object} sessions An array of session objects
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "acctnum": "1551102",
* "handle": "132852",
* "symbol": "EURUSDi",
* "symbol1": "AUDJPYi",
* "symbol2": "CADJPYi",
* "symbol3": "AUDCADi",
* "index": 1,
* "magic": 0,
* "order_status": ""
* }
*
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/GetSession/1'
*/
app.get("/GetSession/:index", function(req, res, index){
try {
if (req.params.index > MAX_SESSIONS || req.params.index > SharedMemory.session_count || req.params.index < 0) {
var temp = new SESSION();
res.json(temp);
} else {
res.json(SharedMemory.session[req.params.index-1]);
}
} catch(error) {
next(error);
}
});
/**
* @api {get} /GetAllSessions Retrieves all sessions
* @apiName GetAllSessions
* @apiGroup Session
*
* @apiSuccess {Object} sessions An array of session objects
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* [
* {
* "acctnum": "1551102",
* "handle": "132852",
* "symbol": "EURUSDi",
* "symbol1": "AUDJPYi",
* "symbol2": "CADJPYi",
* "symbol3": "AUDCADi",
* "index": 1,
* "magic": 0,
* "order_status": ""
* },
* ]
* }
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/GetAllSessions'
*/
app.get("/GetAllSessions", function(req, res, next){
res.json(SharedMemory.session);
});
/**
* @api {get} /GetAllAccounts Retrieves all account
* @apiName GetAllAccounts
* @apiGroup Account
*
* @apiSuccess {Object} sessions An array of session objects
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* [
* {
* "acctnum": "1551102",
* "handle": "132852",
* "symbol": "EURUSDi",
* "symbol1": "AUDJPYi",
* "symbol2": "CADJPYi",
* "symbol3": "AUDCADi",
* "index": 1,
* "magic": 0
* },
* ]
* }
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/GetAllAccounts'
*/
app.get("/GetAllAccounts", function(req, res, next){
res.json(SharedMemory.account);
});
/**
* @api {get} /GetAllCurrencyPairs Retrieves all currency pairs
* @apiName GetAllCurrencyPairs
* @apiGroup Currency
*
* @apiExample {curl} Example usage:
* curl --location --request GET 'http://localhost:3000/GetAllCurrencyPairs'
*
* @apiSuccess {Object} currencies An array of currency objects
*/
app.get("/GetAllCurrencyPairs", function(req, res, next){
res.json(SharedMemory.ccypairs);
});
/**
* @api {get} /GetAllMarketInfo Retrieves all market information
* @apiName GetAllMarketInfo
* @apiGroup Market
*/
app.get("/GetAllMarketInfo", function(req, res, next){
res.json(SharedMemory.marketinfo);
});
/**
* @api {get} /GetMarketInfo Retrieves market information by session
* @apiName GetMarketInfo
* @apiGroup Market
*/
app.get("/GetMarketInfo/:session", function(req, res, next){
try {
if (req.params.session > MAX_SESSIONS || req.params.session > SharedMemory.session_count || req.params.session < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
res.json(SharedMemory.marketinfo[req.params.session-1]);
}
} catch(error) {
next(error);
}
});
/**
* @api {get} /GetMarginInfo Retrieves session margin information
* @apiName GetMarginInfo
* @apiGroup Market
*/
app.get("/GetMarginInfo/:session", function(req, res, next){
try {
if (req.params.session > MAX_SESSIONS || req.params.session > SharedMemory.session_count || req.params.session < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
res.json(SharedMemory.margininfo[req.params.session-1]);
}
} catch(error) {
next(error);
}
});
/**
* @api {get} /GetAllMarginInfo Retrieves all margin information
* @apiName GetAllMarginInfo
* @apiGroup Margin
*/
app.get("/GetAllMarginInfo", function(req, res, next){
res.json(SharedMemory.margininfo);
});
/**
* @api {get} /GetAllResponses Retrieves all responses
* @apiName GetAllResponses
* @apiGroup Utility
*/
app.get("/GetAllResponses", function(req, res, next){
res.json(SharedMemory.response);
});
/**
* @api {get} /GetAllHistory Retrieves all history
* @apiName GetAllHistory
* @apiGroup History
*/
app.get("/GetAllHistory", function(req, res, next){
res.json(SharedMemory.history);
});
/**
* @api {get} /GetAllCurrency1History Retrieves all history for the first currency pair triad
* @apiName GetAllCurrency1History
* @apiGroup History
*/
app.get("/GetAllCurrency1History", function(req, res, next){
res.json(SharedMemory.ccy1history);
});
/**
* @api {get} /GetAllCurrency2History Retrieves all history for the second currency pair triad
* @apiName GetAllCurrency2History
* @apiGroup History
*/
app.get("/GetAllCurrency2History", function(req, res, next){
res.json(SharedMemory.ccy2history);
});
/**
* @api {get} /GetAllCurrency3History Retrieves all history for the third currency pair triad
* @apiName GetAllCurrency3History
* @apiGroup History
*/
app.get("/GetAllCurrency3History", function(req, res, next){
res.json(SharedMemory.ccy3history);
});
/**
* @api {get} /GetAllTradeCommands Retrieves all trade commands
* @apiName GetAllTradeCommands
* @apiGroup Trade
*/
app.get("/GetAllTradeCommands", function(req, res, next){
res.json(SharedMemory.trade_commands);
});
/**
* @api {get} /GetAllPrices Retrieves all prices
* @apiName GetAllPrices
* @apiGroup Trade
*/
app.get("/GetAllPrices", function(req, res, next){
res.json({ "bid": SharedMemory.bid, "ask": SharedMemory.ask, "close": SharedMemory.close, "volume": SharedMemory.volume});
});
/**
* @api {get} /GetDllVersion Retrieves version and copyright information
* @apiName GetDllVersion
* @apiGroup Utility
*/
app.get("/GetDllVersion", function(req, res, next){
var d = new Date();
var pjson = require('./package.json');
res.json("Metatrader API Version " + pjson.version + " - Copyright (c) 2009,2012-2013,2019-" + d.getFullYear() + " PressPage Entertainment Inc DBA PINGLEWARE");
});
app.get("/GetVersion", function(req, res, next){
var pjson = require('./package.json');
res.json(pjson.version);
});
/**
* @api {get} /GetVersion Retrieves version-ONLY
* @apiName GetVersion
* @apiGroup Utility
*/
app.get("/GetVersion", function(req, res, next){
var pjson = require('./package.json');
res.json(pjson.version);
});
/**
* int index,double _bid,double _ask,double _close,double _volume)
*/
/**
* @api {put} /SetBidAsk/:session,:bid,:ask,:close,:volume Set the Bid and Ask price by the session
* @apiName SetBidAsk
* @apiGroup Trade
*
* @apiParam {Number} session The session number
* @apiParam {Number} bid The bid price
* @apiParam {Number} ask The ask price
* @apiParam {Number} close The close price
* @apiParam {Number} volume The volume
*/
app.put("/SetBidAsk/:session,:bid,:ask,:close,:volume", function(req, res, next){
try {
if (req.params.session > MAX_SESSIONS || req.params.session > SharedMemory.session_count || req.params.session < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
SharedMemory.bid[req.params.session-1] = req.params.bid;
SharedMemory.ask[req.params.session-1] = req.params.ask;
SharedMemory.close[req.params.session-1] = req.params.close;
SharedMemory.volume[req.params.session-1] = req.params.volume;
res.json(ERROR_CODES.RET_OK);
}
} catch(error) {
next(error);
}
});
/**
* @api {get} /GetBid/:session Retrieves the bid price by the session
* @apiName GetBid
* @apiGroup Trade
*
* @apiParam {Number} session The session number
*/
app.get("/GetBid/:session", function(req, res, next){
try {
if (req.params.session > MAX_SESSIONS || req.params.session > SharedMemory.session_count || req.params.session < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
res.json(SharedMemory.bid[req.params.session-1]);
}
} catch(error) {
next(error);
}
});
/**
* @api {put} /SetBid/:session,:quote Sets the bid price for the session
* @apiName SetBid
* @apiGroup Trade
*
* @apiParam {Number} session The session number
*/
app.put("/SetBid/:session,:quote", function(req, res, next){
try {
if (req.params.session > MAX_SESSIONS || req.params.session > SharedMemory.session_count || req.params.session < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
SharedMemory.bid[req.params.session-1] = req.params.quote;
res.json(req.params.session);
}
} catch(error) {
next(error);
}
});
/**
* @api {put} /SetBidCurrencyOne/:session,:currency,:quote Sets the bid price for the session
* @apiName SetBidCurrencyOne
* @apiGroup Trade
*
* @apiParam {Number} session The session number
*/
app.put("/SetBidCurrencyOne/:session,:currency,:quote", function(req, res, next){
try {
if (req.params.session > MAX_SESSIONS || req.params.session > SharedMemory.session_count || req.params.session < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
SharedMemory.bid_currency_1[req.params.session-1] = req.params.quote;
SharedMemory.currency_1[req.params.session-1] = req.params.currency;
res.json(req.params.session);
}
} catch(error) {
next(error);
}
});
/**
* @api {put} /SetBidCurrencyTwo/:session,:currency,:quote Sets the bid price for the session
* @apiName SetBidCurrencyTwo
* @apiGroup Trade
*
* @apiParam {Number} session The session number
*/
app.put("/SetBidCurrencyTwo/:session,:currency,:quote", function(req, res, next){
try {
if (req.params.session > MAX_SESSIONS || req.params.session > SharedMemory.session_count || req.params.session < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
SharedMemory.bid_currency_2[req.params.session-1] = req.params.quote;
SharedMemory.currency_2[req.params.session-1] = req.params.currency;
res.json(req.params.session);
}
} catch(error) {
next(error);
}
});
/**
* @api {put} /SetBidCurrencyThree/:session,:currency,:quote Sets the bid price for the session
* @apiName SetBidCurrencyThree
* @apiGroup Trade
*
* @apiParam {Number} session The session number
*/
app.put("/SetBidCurrencyThree/:session,:currency,:quote", function(req, res, next){
try {
if (req.params.session > MAX_SESSIONS || req.params.session > SharedMemory.session_count || req.params.session < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
SharedMemory.bid_currency_3[req.params.session-1] = req.params.quote;
SharedMemory.currency_3[req.params.session-1] = req.params.currency;
res.json(req.params.session);
}
} catch(error) {
next(error);
}
});
/**
* @api {get} /GetAsk/:session Retrieves the ask price by the session
* @apiName GetAsk
* @apiGroup Trade
*
* @apiParam {Number} session The session number
*/
app.get("/GetAsk/:session", function(req, res, next){
try {
if (req.params.session > MAX_SESSIONS || req.params.session > SharedMemory.session_count || req.params.session < 0) {
res.json(ERROR_CODES.RET_ERROR);
} else {
res.json(SharedMemory.ask[req.params.session