UNPKG

@presspage/metatrader-bridge

Version:
1,403 lines (1,297 loc) 154 kB
"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