├── .gitignore ├── MQL5 ├── Experts │ └── Advisors │ │ ├── RestApi.ex5 │ │ └── RestApi.mq5 ├── Include │ ├── RestApi.mqh │ └── json.mqh └── Libraries │ ├── LIBEAY32.dll │ ├── SSLEAY32.dll │ ├── boost_date_time-vc141-mt-x64-1_69.dll │ ├── cpprest_2_10.dll │ ├── docs.html │ ├── mt5-rest.dll │ ├── swagger.json │ └── zlib1.dll ├── README.md ├── mt5-rest.sln └── mt5-rest ├── basic_controller.cpp ├── basic_controller.hpp ├── controller.hpp ├── main.cpp ├── microsvc_controller.cpp ├── microsvc_controller.hpp ├── mt5-rest.def ├── mt5-rest.vcxproj ├── mt5-rest.vcxproj.user ├── network_utils.cpp ├── network_utils.hpp ├── safe_map.cpp ├── safe_map.hpp ├── safe_vector.cpp ├── safe_vector.hpp ├── session_manager.cpp ├── session_manager.hpp ├── std_micro_service.hpp ├── stdafx.cpp ├── stdafx.h ├── targetver.h ├── types.hpp └── usr_interrupt_handler.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | x64 2 | packages 3 | .vs 4 | *.suo 5 | *.user 6 | *.userosscache 7 | ipch/ 8 | *.aps 9 | *.ncb 10 | *.opendb 11 | *.opensdf 12 | *.sdf 13 | *.cachefile 14 | *.VC.db 15 | -------------------------------------------------------------------------------- /MQL5/Experts/Advisors/RestApi.ex5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Experts/Advisors/RestApi.ex5 -------------------------------------------------------------------------------- /MQL5/Experts/Advisors/RestApi.mq5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Experts/Advisors/RestApi.mq5 -------------------------------------------------------------------------------- /MQL5/Include/RestApi.mqh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Include/RestApi.mqh -------------------------------------------------------------------------------- /MQL5/Include/json.mqh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Include/json.mqh -------------------------------------------------------------------------------- /MQL5/Libraries/LIBEAY32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Libraries/LIBEAY32.dll -------------------------------------------------------------------------------- /MQL5/Libraries/SSLEAY32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Libraries/SSLEAY32.dll -------------------------------------------------------------------------------- /MQL5/Libraries/boost_date_time-vc141-mt-x64-1_69.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Libraries/boost_date_time-vc141-mt-x64-1_69.dll -------------------------------------------------------------------------------- /MQL5/Libraries/cpprest_2_10.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Libraries/cpprest_2_10.dll -------------------------------------------------------------------------------- /MQL5/Libraries/docs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 19 |
20 | 21 | -------------------------------------------------------------------------------- /MQL5/Libraries/mt5-rest.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Libraries/mt5-rest.dll -------------------------------------------------------------------------------- /MQL5/Libraries/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger" : "2.0", 3 | "info" : { 4 | "description" : "Turns Metatrader5 into REST API server", 5 | "version" : "1.0.0", 6 | "title" : "Metatrader5 REST API", 7 | "contact" : { 8 | "email" : "mikhail@dev4traders.com" 9 | } 10 | }, 11 | "tags" : [ { 12 | "name" : "symbol", 13 | "description" : "Market symbol" 14 | },{ 15 | "name" : "account", 16 | "description" : "MT5 account" 17 | }, { 18 | "name" : "trade", 19 | "description" : "Trade" 20 | }, { 21 | "name" : "position", 22 | "description" : "Position" 23 | }, { 24 | "name" : "deal", 25 | "description" : "Deal/Transaction" 26 | }, { 27 | "name" : "order", 28 | "description" : "Order" 29 | } ], 30 | "paths" : { 31 | "/info" : { 32 | "get" : { 33 | "tags" : [ "account" ], 34 | "security":[{"apiKey":[]}], 35 | "summary" : "get account info", 36 | "operationId" : "info", 37 | "description" : "Loads Account balance, broker, name, etc..\n", 38 | "produces" : [ "application/json" ], 39 | "responses" : { 40 | "200" : { 41 | "description" : "info in json", 42 | "schema" : { 43 | "$ref" : "#/definitions/AccountItem" 44 | } 45 | }, 46 | "400" : { 47 | "description" : "bad input parameter" 48 | } 49 | } 50 | } 51 | }, 52 | "/balance" : { 53 | "get" : { 54 | "tags" : [ "account" ], 55 | "security":[{"apiKey":[]}], 56 | "summary" : "get account balance", 57 | "operationId" : "balance", 58 | "description" : "Loads Account balance, margin, free margin\n", 59 | "produces" : [ "application/json" ], 60 | "responses" : { 61 | "200" : { 62 | "description" : "balance info in json", 63 | "schema" : { 64 | "$ref" : "#/definitions/BalanceItem" 65 | } 66 | }, 67 | "400" : { 68 | "description" : "bad input parameter" 69 | } 70 | } 71 | } 72 | }, 73 | "/symbols/{name}" : { 74 | "get" : { 75 | "tags" : [ "symbol" ], 76 | "parameters":[{"name":"name","in":"path","required":true,"type":"string"}], 77 | "security":[{"apiKey":[]}], 78 | "summary" : "get symbol info", 79 | "operationId" : "symbol", 80 | "description" : "Loads Symbol info by name\n", 81 | "produces" : [ "application/json" ], 82 | "responses" : { 83 | "200" : { 84 | "description" : "bid/ask in json", 85 | "schema" : { 86 | "$ref" : "#/definitions/Symbol" 87 | } 88 | }, 89 | "400" : { 90 | "description" : "bad input parameter" 91 | } 92 | } 93 | } 94 | }, 95 | "/orders" : { 96 | "get" : { 97 | "tags" : [ "order" ], 98 | "security":[{"apiKey":[]}], 99 | "summary" : "get account orders", 100 | "operationId" : "orders", 101 | "description" : "Loads Account Orders\n", 102 | "produces" : [ "application/json" ], 103 | "responses" : { 104 | "200" : { 105 | "description" : "orders array in json", 106 | "schema" : { 107 | "$ref" : "#/definitions/ArrayOfOrders" 108 | } 109 | }, 110 | "400" : { 111 | "description" : "bad input parameter" 112 | } 113 | } 114 | } 115 | }, 116 | "/orders/{id}" : { 117 | "get" : { 118 | "tags" : [ "order" ], 119 | "parameters":[{"name":"id","in":"path","required":true,"type":"string"}], 120 | "security":[{"apiKey":[]}], 121 | "summary" : "get account order", 122 | "operationId" : "order", 123 | "description" : "Loads Account Order by id\n", 124 | "produces" : [ "application/json" ], 125 | "responses" : { 126 | "200" : { 127 | "description" : "order in json", 128 | "schema" : { 129 | "$ref" : "#/definitions/Order" 130 | } 131 | }, 132 | "400" : { 133 | "description" : "bad input parameter" 134 | } 135 | } 136 | } 137 | }, 138 | "/history" : { 139 | "get" : { 140 | "tags" : [ "order" ], 141 | "security":[{"apiKey":[]}], 142 | "summary" : "get account orders history", 143 | "operationId" : "orders_history", 144 | "description" : "Loads Account Orders History\n", 145 | "produces" : [ "application/json" ], 146 | "responses" : { 147 | "200" : { 148 | "description" : "orders array in json", 149 | "schema" : { 150 | "$ref" : "#/definitions/ArrayOfOrdersHistory" 151 | } 152 | }, 153 | "400" : { 154 | "description" : "bad input parameter" 155 | } 156 | } 157 | } 158 | }, 159 | "/history/{id}" : { 160 | "get" : { 161 | "tags" : [ "order" ], 162 | "parameters":[{"name":"id","in":"path","required":true,"type":"string"}], 163 | "security":[{"apiKey":[]}], 164 | "summary" : "get account order from history", 165 | "operationId" : "order_history", 166 | "description" : "Loads Account Order from History by id\n", 167 | "produces" : [ "application/json" ], 168 | "responses" : { 169 | "200" : { 170 | "description" : "order in json", 171 | "schema" : { 172 | "$ref" : "#/definitions/OrderHistory" 173 | } 174 | }, 175 | "400" : { 176 | "description" : "bad input parameter" 177 | } 178 | } 179 | } 180 | }, 181 | "/deals?offset={offset}&limit={limit}" : { 182 | "get" : { 183 | "tags" : [ "deal" ], 184 | "security":[{"apiKey":[]}], 185 | "summary" : "get account deals", 186 | "operationId" : "dealrequest", 187 | "description" : "Loads Account Deals\n", 188 | "produces" : [ "application/json" ], 189 | "parameters" : [ 190 | { 191 | "in" : "query", 192 | "name" : "offset", 193 | "required" : true, 194 | "schema" : { 195 | "type" : "string" 196 | } 197 | }, 198 | { 199 | "in" : "query", 200 | "name" : "limit", 201 | "required" : true, 202 | "schema" : { 203 | "type" : "string" 204 | } 205 | } ], 206 | "responses" : { 207 | "200" : { 208 | "description" : "deals array in json", 209 | "schema" : { 210 | "$ref" : "#/definitions/ArrayOfDeals" 211 | } 212 | }, 213 | "400" : { 214 | "description" : "bad input parameter" 215 | } 216 | } 217 | } 218 | }, 219 | "/deals/{id}" : { 220 | "get" : { 221 | "tags" : [ "deal" ], 222 | "parameters":[{"name":"id","in":"path","required":true,"type":"string"}], 223 | "security":[{"apiKey":[]}], 224 | "summary" : "get account deals", 225 | "operationId" : "deals", 226 | "description" : "Loads Account Deals by id\n", 227 | "produces" : [ "application/json" ], 228 | "responses" : { 229 | "200" : { 230 | "description" : "Deal in json", 231 | "schema" : { 232 | "$ref" : "#/definitions/Deal" 233 | } 234 | }, 235 | "400" : { 236 | "description" : "bad input parameter" 237 | } 238 | } 239 | } 240 | }, 241 | "/positions" : { 242 | "get" : { 243 | "tags" : [ "position" ], 244 | "security":[{"apiKey":[]}], 245 | "summary" : "get account positions", 246 | "operationId" : "positions", 247 | "description" : "Loads Account Positions\n", 248 | "produces" : [ "application/json" ], 249 | "responses" : { 250 | "200" : { 251 | "description" : "positions array in json", 252 | "schema" : { 253 | "$ref" : "#/definitions/ArrayOfPositions" 254 | } 255 | }, 256 | "400" : { 257 | "description" : "bad input parameter" 258 | } 259 | } 260 | } 261 | }, 262 | "/positions/{id}" : { 263 | "get" : { 264 | "tags" : [ "position" ], 265 | "parameters":[{"name":"id","in":"path","required":true,"type":"string"}], 266 | "security":[{"apiKey":[]}], 267 | "summary" : "get account position", 268 | "operationId" : "position", 269 | "description" : "Loads Account Position by id\n", 270 | "produces" : [ "application/json" ], 271 | "responses" : { 272 | "200" : { 273 | "description" : "position in json", 274 | "schema" : { 275 | "$ref" : "#/definitions/Position" 276 | } 277 | }, 278 | "400" : { 279 | "description" : "bad input parameter" 280 | } 281 | } 282 | } 283 | }, 284 | "/trade" : { 285 | "post" : { 286 | "tags" : [ "trade" ], 287 | "security":[{"apiKey":[]}], 288 | "summary" : "Send Order", 289 | "produces" : [ "application/json" ], 290 | "consumes" : [ "application/json" ], 291 | "parameters" : [ { 292 | "in" : "body", 293 | "name" : "body", 294 | "description" : "{\"actionType\": \"ORDER_TYPE_BUY\" }", 295 | "required" : true, 296 | "schema" : { 297 | "$ref" : "#/definitions/TradeInput" 298 | } 299 | } ], 300 | "responses" : { 301 | "200" : { 302 | "description" : "successful operation", 303 | "schema" : { 304 | "$ref" : "#/definitions/TradeReturn" 305 | } 306 | }, 307 | "400" : { 308 | "description" : "bad input parameter" 309 | } 310 | } 311 | } 312 | } 313 | }, 314 | "securityDefinitions": { 315 | "apiKey": { 316 | "type": "apiKey", 317 | "in": "header", 318 | "name": "Authorization" 319 | } 320 | }, 321 | "definitions" : { 322 | "TradeInput" : { 323 | "type" : "object", 324 | "properties" : { 325 | "id" : { 326 | "type" : "integer", 327 | "example" : 1 328 | }, 329 | "symbol" : { 330 | "type" : "string", 331 | "example" : "EURUSD" 332 | }, 333 | "actionType" : { 334 | "type" : "string", 335 | "enum" : [ "ORDER_TYPE_SELL", "ORDER_TYPE_BUY", "ORDER_TYPE_BUY_LIMIT", "ORDER_TYPE_SELL_LIMIT", "ORDER_TYPE_BUY_STOP", "ORDER_TYPE_SELL_STOP", "POSITION_MODIFY", "POSITION_PARTIAL", "POSITION_CLOSE_ID", "POSITION_CLOSE_SYMBOL", "ORDER_MODIFY", "ORDER_CANCEL" ] 336 | }, 337 | "volume" : { 338 | "type" : "number", 339 | "example" : 0.1 340 | }, 341 | "price" : { 342 | "type" : "number", 343 | "example" : 1.12121 344 | }, 345 | "stoploss" : { 346 | "type" : "number", 347 | "example" : 1.12121 348 | }, 349 | "takeprofit" : { 350 | "type" : "number", 351 | "example" : 1.12121 352 | } 353 | } 354 | }, 355 | "TradeReturn" : { 356 | "type" : "object", 357 | "properties" : { 358 | "error" : { 359 | "type" : "integer", 360 | "example" : 6533 361 | }, 362 | "description" : { 363 | "type" : "string", 364 | "example" : "ERR_WRONG_ACTION" 365 | } 366 | } 367 | }, 368 | "Symbol" : { 369 | "type" : "object", 370 | "properties" : { 371 | "ask" : { 372 | "type" : "number", 373 | "example" : 1.22323 374 | }, 375 | "bid" : { 376 | "type" : "number", 377 | "example" : 1.34341 378 | } 379 | } 380 | }, 381 | "AccountItem" : { 382 | "type" : "object", 383 | "properties" : { 384 | "currency" : { 385 | "type" : "string", 386 | "example" : "USD" 387 | }, 388 | "server" : { 389 | "type" : "string", 390 | "example" : "MetaQuotes-Demo" 391 | }, 392 | "broker" : { 393 | "type" : "string", 394 | "example" : "MetaQuotes Software Corp." 395 | }, 396 | "balance" : { 397 | "type" : "number", 398 | "example" : 1000.0 399 | }, 400 | "equity" : { 401 | "type" : "number", 402 | "example" : 1000.0 403 | }, 404 | "margin" : { 405 | "type" : "number", 406 | "example" : 1000.0 407 | }, 408 | "margin_free" : { 409 | "type" : "number", 410 | "example" : 1000.0 411 | }, 412 | "margin_level" : { 413 | "type" : "number", 414 | "example" : 1000.0 415 | }, 416 | "orders_total" : { 417 | "type" : "integer", 418 | "example" : 2 419 | }, 420 | "positions_total" : { 421 | "type" : "integer", 422 | "example" : 2 423 | } 424 | } 425 | }, 426 | "BalanceItem" : { 427 | "type" : "object", 428 | "properties" : { 429 | "balance" : { 430 | "type" : "number", 431 | "example" : 1000.0 432 | }, 433 | "equity" : { 434 | "type" : "number", 435 | "example" : 1000.0 436 | }, 437 | "margin" : { 438 | "type" : "number", 439 | "example" : 1000.0 440 | }, 441 | "margin_free" : { 442 | "type" : "number", 443 | "example" : 1000.0 444 | } 445 | } 446 | }, 447 | "ArrayOfOrders" : { 448 | "type" : "array", 449 | "items" : { 450 | "type" : "object", 451 | "properties" : { 452 | "id" : { 453 | "type" : "integer", 454 | "example" : 1 455 | }, 456 | "type" : { 457 | "type" : "string", 458 | "enum" : [ "ORDER_TYPE_SELL", "ORDER_TYPE_BUY", "ORDER_TYPE_BUY_LIMIT", "ORDER_TYPE_SELL_LIMIT", "ORDER_TYPE_BUY_STOP", "ORDER_TYPE_SELL_STOP", "POSITION_MODIFY", "POSITION_PARTIAL", "POSITION_CLOSE_ID", "POSITION_CLOSE_SYMBOL", "ORDER_MODIFY", "ORDER_CANCEL" ] 459 | }, 460 | "magic" : { 461 | "type" : "integer", 462 | "example" : 0 463 | }, 464 | "symbol" : { 465 | "type" : "string", 466 | "example" : "EURUSD" 467 | }, 468 | "time_setup" : { 469 | "type" : "string", 470 | "example" : "2019-06-05T19:35:50.000Z" 471 | }, 472 | "open" : { 473 | "type" : "number", 474 | "example" : 1.65656 475 | }, 476 | "stoploss" : { 477 | "type" : "number", 478 | "example" : 1.65656 479 | }, 480 | "takeprofit" : { 481 | "type" : "number", 482 | "example" : 1.65656 483 | }, 484 | "volume" : { 485 | "type" : "number", 486 | "example" : 0.1 487 | } 488 | } 489 | } 490 | }, 491 | "Order" : { 492 | "type" : "object", 493 | "properties" : { 494 | "id" : { 495 | "type" : "integer", 496 | "example" : 1 497 | }, 498 | "type" : { 499 | "type" : "string", 500 | "enum" : [ "ORDER_TYPE_SELL", "ORDER_TYPE_BUY", "ORDER_TYPE_BUY_LIMIT", "ORDER_TYPE_SELL_LIMIT", "ORDER_TYPE_BUY_STOP", "ORDER_TYPE_SELL_STOP", "POSITION_MODIFY", "POSITION_PARTIAL", "POSITION_CLOSE_ID", "POSITION_CLOSE_SYMBOL", "ORDER_MODIFY", "ORDER_CANCEL" ] 501 | }, 502 | "magic" : { 503 | "type" : "integer", 504 | "example" : 0 505 | }, 506 | "symbol" : { 507 | "type" : "string", 508 | "example" : "EURUSD" 509 | }, 510 | "time_setup" : { 511 | "type" : "string", 512 | "example" : "2019-06-05T19:35:50.000Z" 513 | }, 514 | "open" : { 515 | "type" : "number", 516 | "example" : 1.65656 517 | }, 518 | "stoploss" : { 519 | "type" : "number", 520 | "example" : 1.65656 521 | }, 522 | "takeprofit" : { 523 | "type" : "number", 524 | "example" : 1.65656 525 | }, 526 | "volume" : { 527 | "type" : "number", 528 | "example" : 0.1 529 | } 530 | } 531 | }, 532 | "ArrayOfOrdersHistory" : { 533 | "type" : "array", 534 | "items" : { 535 | "type" : "object", 536 | "properties" : { 537 | "id" : { 538 | "type" : "integer", 539 | "example" : 1 540 | }, 541 | "type" : { 542 | "type" : "string", 543 | "enum" : [ "ORDER_TYPE_SELL", "ORDER_TYPE_BUY", "ORDER_TYPE_BUY_LIMIT", "ORDER_TYPE_SELL_LIMIT", "ORDER_TYPE_BUY_STOP", "ORDER_TYPE_SELL_STOP", "POSITION_MODIFY", "POSITION_PARTIAL", "POSITION_CLOSE_ID", "POSITION_CLOSE_SYMBOL", "ORDER_MODIFY", "ORDER_CANCEL" ] 544 | }, 545 | "state" : { 546 | "type" : "string", 547 | "enum" : [ "ORDER_STATE_STARTED", "ORDER_STATE_PLACED", "ORDER_STATE_CANCELED", "ORDER_STATE_PARTIAL", "ORDER_STATE_FILLED", "ORDER_STATE_REJECTED", "ORDER_STATE_EXPIRED", "ORDER_STATE_REQUEST_ADD", "ORDER_STATE_REQUEST_MODIFY", "ORDER_STATE_REQUEST_CANCEL" ] 548 | }, 549 | "magic" : { 550 | "type" : "integer", 551 | "example" : 0 552 | }, 553 | "symbol" : { 554 | "type" : "string", 555 | "example" : "EURUSD" 556 | }, 557 | "time_setup" : { 558 | "type" : "string", 559 | "example" : "2019-06-05T19:35:50.000Z" 560 | }, 561 | "time_done" : { 562 | "type" : "string", 563 | "example" : "2019-06-05T19:35:50.000Z" 564 | }, 565 | "open" : { 566 | "type" : "number", 567 | "example" : 1.65656 568 | }, 569 | "stoploss" : { 570 | "type" : "number", 571 | "example" : 1.65656 572 | }, 573 | "takeprofit" : { 574 | "type" : "number", 575 | "example" : 1.65656 576 | }, 577 | "volume" : { 578 | "type" : "number", 579 | "example" : 0.1 580 | } 581 | } 582 | } 583 | }, 584 | "OrderHistory" : { 585 | "type" : "object", 586 | "properties" : { 587 | "id" : { 588 | "type" : "integer", 589 | "example" : 1 590 | }, 591 | "type" : { 592 | "type" : "string", 593 | "enum" : [ "ORDER_TYPE_SELL", "ORDER_TYPE_BUY", "ORDER_TYPE_BUY_LIMIT", "ORDER_TYPE_SELL_LIMIT", "ORDER_TYPE_BUY_STOP", "ORDER_TYPE_SELL_STOP", "POSITION_MODIFY", "POSITION_PARTIAL", "POSITION_CLOSE_ID", "POSITION_CLOSE_SYMBOL", "ORDER_MODIFY", "ORDER_CANCEL" ] 594 | }, 595 | "state" : { 596 | "type" : "string", 597 | "enum" : [ "ORDER_STATE_STARTED", "ORDER_STATE_PLACED", "ORDER_STATE_CANCELED", "ORDER_STATE_PARTIAL", "ORDER_STATE_FILLED", "ORDER_STATE_REJECTED", "ORDER_STATE_EXPIRED", "ORDER_STATE_REQUEST_ADD", "ORDER_STATE_REQUEST_MODIFY", "ORDER_STATE_REQUEST_CANCEL" ] 598 | }, 599 | "magic" : { 600 | "type" : "integer", 601 | "example" : 0 602 | }, 603 | "symbol" : { 604 | "type" : "string", 605 | "example" : "EURUSD" 606 | }, 607 | "time_setup" : { 608 | "type" : "string", 609 | "example" : "2019-06-05T19:35:50.000Z" 610 | }, 611 | "time_done" : { 612 | "type" : "string", 613 | "example" : "2019-06-05T19:35:50.000Z" 614 | }, 615 | "open" : { 616 | "type" : "number", 617 | "example" : 1.65656 618 | }, 619 | "stoploss" : { 620 | "type" : "number", 621 | "example" : 1.65656 622 | }, 623 | "takeprofit" : { 624 | "type" : "number", 625 | "example" : 1.65656 626 | }, 627 | "volume" : { 628 | "type" : "number", 629 | "example" : 0.1 630 | } 631 | } 632 | }, 633 | "ArrayOfDeals" : { 634 | "type" : "array", 635 | "items" : { 636 | "type" : "object", 637 | "properties" : { 638 | "id" : { 639 | "type" : "integer", 640 | "example" : 1 641 | }, 642 | "price" : { 643 | "type" : "number", 644 | "example" : 1.65656 645 | }, 646 | "commission" : { 647 | "type" : "number", 648 | "example" : 0.1 649 | }, 650 | "time" : { 651 | "type" : "string", 652 | "example" : "2019-06-05T19:35:50.000Z" 653 | }, 654 | "symbol" : { 655 | "type" : "string", 656 | "example" : "EURUSD" 657 | }, 658 | "type" : { 659 | "type" : "string", 660 | "enum": [ "DEAL_TYPE_BUY", "DEAL_TYPE_SELL", "DEAL_TYPE_BALANCE", "DEAL_TYPE_CREDIT", "DEAL_TYPE_CHARGE", "DEAL_TYPE_CORRECTION", "DEAL_TYPE_BONUS", "DEAL_TYPE_COMMISSION", "DEAL_TYPE_COMMISSION_DAILY", "DEAL_TYPE_COMMISSION_MONTHLY", "DEAL_TYPE_COMMISSION_AGENT_DAILY", "DEAL_TYPE_COMMISSION_AGENT_MONTHLY", "DEAL_TYPE_INTEREST", "DEAL_TYPE_BUY_CANCELED", "DEAL_TYPE_SELL_CANCELED", "DEAL_DIVIDEND", "DEAL_DIVIDEND_FRANKED", "DEAL_TAX" ] 661 | }, 662 | "profit" : { 663 | "type" : "number", 664 | "example" : 0.1 665 | }, 666 | "volume" : { 667 | "type" : "number", 668 | "example" : 0.1 669 | }, 670 | "position_id" : { 671 | "type" : "integer", 672 | "example" : 1 673 | }, 674 | "order_id" : { 675 | "type" : "integer", 676 | "example" : 1 677 | } 678 | } 679 | } 680 | }, 681 | "Deal" : { 682 | "type" : "object", 683 | "properties" : { 684 | "id" : { 685 | "type" : "integer", 686 | "example" : 1 687 | }, 688 | "price" : { 689 | "type" : "number", 690 | "example" : 1.65656 691 | }, 692 | "commission" : { 693 | "type" : "number", 694 | "example" : 0.1 695 | }, 696 | "time" : { 697 | "type" : "string", 698 | "example" : "2019-06-05T19:35:50.000Z" 699 | }, 700 | "symbol" : { 701 | "type" : "string", 702 | "example" : "EURUSD" 703 | }, 704 | "type" : { 705 | "type" : "string", 706 | "enum": [ "DEAL_TYPE_BUY", "DEAL_TYPE_SELL", "DEAL_TYPE_BALANCE", "DEAL_TYPE_CREDIT", "DEAL_TYPE_CHARGE", "DEAL_TYPE_CORRECTION", "DEAL_TYPE_BONUS", "DEAL_TYPE_COMMISSION", "DEAL_TYPE_COMMISSION_DAILY", "DEAL_TYPE_COMMISSION_MONTHLY", "DEAL_TYPE_COMMISSION_AGENT_DAILY", "DEAL_TYPE_COMMISSION_AGENT_MONTHLY", "DEAL_TYPE_INTEREST", "DEAL_TYPE_BUY_CANCELED", "DEAL_TYPE_SELL_CANCELED", "DEAL_DIVIDEND", "DEAL_DIVIDEND_FRANKED", "DEAL_TAX" ] 707 | }, 708 | "profit" : { 709 | "type" : "number", 710 | "example" : 0.1 711 | }, 712 | "volume" : { 713 | "type" : "number", 714 | "example" : 0.1 715 | }, 716 | "position_id" : { 717 | "type" : "integer", 718 | "example" : 1 719 | }, 720 | "order_id" : { 721 | "type" : "integer", 722 | "example" : 1 723 | } 724 | } 725 | }, 726 | "Position" : { 727 | "type" : "object", 728 | "properties" : { 729 | "id" : { 730 | "type" : "integer", 731 | "example" : 1 732 | }, 733 | "type" : { 734 | "type" : "string", 735 | "enum": ["POSITION_TYPE_BUY", "POSITION_TYPE_SELL"] 736 | }, 737 | "magic" : { 738 | "type" : "integer", 739 | "example" : 0 740 | }, 741 | "symbol" : { 742 | "type" : "string", 743 | "example" : "EURUSD" 744 | }, 745 | "time_setup" : { 746 | "type" : "string", 747 | "example" : "2019-06-05T19:35:50.000Z" 748 | }, 749 | "open" : { 750 | "type" : "number", 751 | "example" : 1.65656 752 | }, 753 | "price_current" : { 754 | "type" : "number", 755 | "example" : 1.65656 756 | }, 757 | "stoploss" : { 758 | "type" : "number", 759 | "example" : 1.65656 760 | }, 761 | "takeprofit" : { 762 | "type" : "number", 763 | "example" : 1.65656 764 | }, 765 | "volume" : { 766 | "type" : "number", 767 | "example" : 0.1 768 | } 769 | } 770 | }, 771 | "ArrayOfPositions" : { 772 | "type" : "array", 773 | "items" : { 774 | "type" : "object", 775 | "properties" : { 776 | "id" : { 777 | "type" : "integer", 778 | "example" : 1 779 | }, 780 | "type" : { 781 | "type" : "string", 782 | "enum": ["POSITION_TYPE_BUY", "POSITION_TYPE_SELL"] 783 | }, 784 | "magic" : { 785 | "type" : "integer", 786 | "example" : 0 787 | }, 788 | "symbol" : { 789 | "type" : "string", 790 | "example" : "EURUSD" 791 | }, 792 | "time_setup" : { 793 | "type" : "string", 794 | "example" : "2019-06-05T19:35:50.000Z" 795 | }, 796 | "open" : { 797 | "type" : "number", 798 | "example" : 1.65656 799 | }, 800 | "price_current" : { 801 | "type" : "number", 802 | "example" : 1.65656 803 | }, 804 | "stoploss" : { 805 | "type" : "number", 806 | "example" : 1.65656 807 | }, 808 | "takeprofit" : { 809 | "type" : "number", 810 | "example" : 1.65656 811 | }, 812 | "volume" : { 813 | "type" : "number", 814 | "example" : 0.1 815 | } 816 | } 817 | } 818 | } 819 | }, 820 | "host" : "localhost:6542", 821 | "schemes" : [ "http" ] 822 | } -------------------------------------------------------------------------------- /MQL5/Libraries/zlib1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/MQL5/Libraries/zlib1.dll -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Turns Metatrader5 into REST API server. 2 | 3 | Note: make sure you have VSredist: https://www.microsoft.com/en-ie/download/details.aspx?id=48145 4 | 5 | time_setup, time is MQL5 datetime, check docs at: https://www.mql5.com/en/docs/basis/types/integer/datetime 6 | 7 | check "error" for /trade command on that page: https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes 8 | 9 | for enums check that page: https://www.mql5.com/en/docs/constants 10 | 11 | ## how to compile 12 | clone repo to any folder on our PC. 13 | 14 | Copy MQL5 folder to Data folder of mt5 (how to get where is Data folder is localted, open mt5, click File->Open Data Folder or just click Ctrl+Shft+D). 15 | In MT5 Navigator (to show Naavigator click Ctrl+N) select Expert Advisors->Advisors. Right click on RestApi, select Modify. Editor will be opened, press F7 to compile. Done. 16 | 17 | To compile C++ dll use Visual Studio 2017. Use .sln file to open solution in VS, select Realease x64 and press Ctrl+Shft+b to build dll file. Output is located under /x64 folder. 18 | 19 | 20 | ## Commands 21 | 22 | POST /sub - setup web hook. options: callback_url and callback_format (json or x-form) 23 | 24 | GET /symbols/{name} - get symbol informaiton including ask/bid prices. 25 | 26 | GET /info - get account details, number of orders, number of positions 27 | 28 | GET /positions - returns list of positions 29 | 30 | GET /positions/{id} - return position by id 31 | 32 | GET /deals?offset={offset}&limit={limit} - returns list of deals/transactions 33 | 34 | GET /deals/{id} - return deal by id 35 | 36 | GET /orders - returns list of orders 37 | 38 | GET /orders/{id} - return order by id 39 | 40 | GET /history - returns list of history orders 41 | 42 | GET /history/{id} - return order history by id 43 | 44 | POST /trade - open position, details in POST body 45 | 46 | # Example of POST body for trade command 47 | 48 | ## Open Buy 49 | ```json 50 | { 51 | "symbol":"EURUSD", 52 | "actionType": "ORDER_TYPE_BUY", 53 | "volume": 0.1, 54 | "stoploss": 1.3455, 55 | "takeprofit": 1.33333, 56 | "comment": "test buy" 57 | } 58 | ``` 59 | 60 | ## Open Sell 61 | ```json 62 | { 63 | "symbol":"EURUSD", 64 | "actionType": "ORDER_TYPE_SELL", 65 | "volume": 0.1, 66 | "stoploss": 1.3455, 67 | "takeprofit": 1.33333, 68 | "comment": "test buy" 69 | } 70 | ``` 71 | 72 | ## Open Buy Limit 73 | ```json 74 | { 75 | "symbol":"EURUSD", 76 | "actionType": "ORDER_TYPE_BUY_LIMIT", 77 | "price": 1.4444, 78 | "volume": 0.1, 79 | "stoploss": 1.3455, 80 | "takeprofit": 1.33333, 81 | "comment": "test buy limit" 82 | } 83 | ``` 84 | 85 | ## Open Sell Limit 86 | ```json 87 | { 88 | "symbol":"EURUSD", 89 | "actionType": "ORDER_TYPE_SELL_LIMIT", 90 | "price": 1.4444, 91 | "volume": 0.1, 92 | "stoploss": 1.3455, 93 | "takeprofit": 1.33333, 94 | "comment": "test sell limit" 95 | } 96 | ``` 97 | 98 | ## Open Buy Stop 99 | ```json 100 | { 101 | "symbol":"EURUSD", 102 | "actionType": 103 | "ORDER_TYPE_BUY_STOP", 104 | "price": 1.4444, 105 | "volume": 0.1, 106 | "stoploss": 1.3455, 107 | "takeprofit": 1.33333, 108 | "comment": "test buy stop" 109 | } 110 | ``` 111 | 112 | ## Open Sell Stop 113 | ```json 114 | { 115 | "symbol":"EURUSD", 116 | "actionType": "ORDER_TYPE_SELL_STOP", 117 | "price": 1.4444, 118 | "volume": 0.1, 119 | "stoploss": 1.3455, 120 | "takeprofit": 1.33333, 121 | "comment": "test sell stop" 122 | } 123 | ``` 124 | 125 | ## Position Close by ID 126 | ```json 127 | { "actionType": "POSITION_CLOSE_ID", "id": 1212121 } 128 | ``` 129 | 130 | ## Order Cancel 131 | ```json 132 | { "actionType": "ORDER_CANCEL", "id": 1212121 } 133 | ``` 134 | 135 | ## Order Cancel 136 | ```json 137 | { "actionType": "POSITION_PARTIAL", "id": 1212121, "volume": 0.1 } 138 | ``` 139 | 140 | 141 | # Examples of /trade output 142 | ```json 143 | { 144 | "error": 10018, 145 | "desription": "TRADE_RETCODE_MARKET_CLOSED", 146 | "order_id": 0, 147 | "volume": 0, 148 | "price": 0, 149 | "bid": 0, 150 | "ask": 0, 151 | "function": "CRestApi::tradingModule" 152 | } 153 | ``` 154 | ```json 155 | { 156 | "error": 10009, 157 | "desription": "TRADE_RETCODE_DONE", 158 | "order_id": 405895526, 159 | "volume": 0.1, 160 | "price": 1.13047, 161 | "bid": 1.13038, 162 | "ask": 1.13047, 163 | "function": "CRestApi::tradingModule" 164 | } 165 | ``` 166 | -------------------------------------------------------------------------------- /mt5-rest.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mt4-rest", "mt5-rest\mt5-rest.vcxproj", "{7359E8DF-CF85-409D-833B-3B66F8DAC462}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {7359E8DF-CF85-409D-833B-3B66F8DAC462}.Debug|x64.ActiveCfg = Debug|x64 17 | {7359E8DF-CF85-409D-833B-3B66F8DAC462}.Debug|x64.Build.0 = Debug|x64 18 | {7359E8DF-CF85-409D-833B-3B66F8DAC462}.Debug|x86.ActiveCfg = Debug|Win32 19 | {7359E8DF-CF85-409D-833B-3B66F8DAC462}.Debug|x86.Build.0 = Debug|Win32 20 | {7359E8DF-CF85-409D-833B-3B66F8DAC462}.Release|x64.ActiveCfg = Release|x64 21 | {7359E8DF-CF85-409D-833B-3B66F8DAC462}.Release|x64.Build.0 = Release|x64 22 | {7359E8DF-CF85-409D-833B-3B66F8DAC462}.Release|x86.ActiveCfg = Release|Win32 23 | {7359E8DF-CF85-409D-833B-3B66F8DAC462}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {08964258-A61B-48D7-9E07-0818CDD29B8B} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /mt5-rest/basic_controller.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "network_utils.hpp" // -> these two lines must stay in this order, boost/cpprestsdk header include order breaks "U" 3 | #include "basic_controller.hpp" // -| 4 | 5 | namespace cfx { 6 | BasicController::BasicController() { 7 | 8 | } 9 | 10 | BasicController::~BasicController() { 11 | 12 | } 13 | void BasicController::setEndpoint(const utility::string_t & value) { 14 | uri endpointURI(value); 15 | uri_builder endpointBuilder; 16 | 17 | endpointBuilder.set_scheme(endpointURI.scheme()); 18 | 19 | if (endpointURI.host() == U("host_auto_ip4")) { 20 | endpointBuilder.set_host(NetworkUtils::hostIP4()); 21 | } 22 | else if (endpointURI.host() == U("host_auto_ip6")) { 23 | endpointBuilder.set_host(NetworkUtils::hostIP6()); 24 | } 25 | else { 26 | endpointBuilder.set_host(endpointURI.host()); 27 | } 28 | endpointBuilder.set_port(endpointURI.port()); 29 | endpointBuilder.set_path(endpointURI.path()); 30 | 31 | _listener = http_listener(endpointBuilder.to_uri()); 32 | } 33 | 34 | utility::string_t BasicController::endpoint() const { 35 | return _listener.uri().to_string(); 36 | } 37 | 38 | utility::string_t BasicController::getHostPort() const { 39 | return _listener.uri().host() + L":" + std::to_wstring( _listener.uri().port() ); 40 | } 41 | 42 | pplx::task BasicController::accept() { 43 | initRestOpHandlers(); 44 | return _listener.open(); 45 | } 46 | 47 | pplx::task BasicController::shutdown() { 48 | return _listener.close(); 49 | } 50 | 51 | std::vector BasicController::requestPath(const http_request & message) { 52 | auto relativePath = uri::decode(message.relative_uri().path()); 53 | return uri::split_path(relativePath); 54 | } 55 | 56 | std::map BasicController::requestQueryParams(const http_request & message) { 57 | auto query = message.relative_uri().query(); 58 | return uri::split_query(query); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /mt5-rest/basic_controller.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "controller.hpp" 7 | 8 | using namespace web; 9 | using namespace http::experimental::listener; 10 | 11 | namespace cfx { 12 | class BasicController { 13 | protected: 14 | http_listener _listener; // main micro service network endpoint 15 | 16 | public: 17 | BasicController(); 18 | ~BasicController(); 19 | 20 | void setEndpoint(const utility::string_t & value); 21 | utility::string_t endpoint() const; 22 | utility::string_t getHostPort() const; 23 | pplx::task accept(); 24 | pplx::task shutdown(); 25 | 26 | virtual void initRestOpHandlers() { 27 | /* had to be implemented by the child class */ 28 | } 29 | 30 | std::vector requestPath(const http_request & message); 31 | std::map requestQueryParams(const http_request & message); 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /mt5-rest/controller.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Mejia on 12/03/16. 3 | // 4 | // MIT License 5 | // 6 | // Copyright (c) 2016 ivmeroLabs. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | 27 | #pragma once 28 | 29 | #include 30 | 31 | using namespace web; 32 | using namespace http; 33 | 34 | namespace cfx { 35 | 36 | /*! 37 | * Dispatcher class represents the basic interface for a 38 | * web serivce handler. 39 | */ 40 | class Controller { 41 | public: 42 | virtual void handleGet(http_request message) = 0; 43 | virtual void handlePut(http_request message) = 0; 44 | virtual void handlePost(http_request message) = 0; 45 | virtual void handleDelete(http_request message) = 0; 46 | virtual void handlePatch(http_request messge) = 0; 47 | virtual void handleHead(http_request message) = 0; 48 | virtual void handleOptions(http_request message) = 0; 49 | virtual void handleTrace(http_request message) = 0; 50 | virtual void handleConnect(http_request message) = 0; 51 | virtual void handleMerge(http_request message) = 0; 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /mt5-rest/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/mt5-rest/main.cpp -------------------------------------------------------------------------------- /mt5-rest/microsvc_controller.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "stdafx.h" 5 | #include "microsvc_controller.hpp" 6 | #include "types.hpp" 7 | 8 | #define CMD_DOCS L"docs" 9 | #define CMD_SUB L"sub" 10 | #define CMD_SWAGGER L"swagger.json" 11 | #define CMD_VERSION L"version" 12 | 13 | using namespace web; 14 | using namespace http; 15 | 16 | void MicroserviceController::initRestOpHandlers() { 17 | _listener.support(methods::GET, std::bind(&MicroserviceController::handleGet, this, std::placeholders::_1)); 18 | _listener.support(methods::PUT, std::bind(&MicroserviceController::handlePut, this, std::placeholders::_1)); 19 | _listener.support(methods::POST, std::bind(&MicroserviceController::handlePost, this, std::placeholders::_1)); 20 | _listener.support(methods::DEL, std::bind(&MicroserviceController::handleDelete, this, std::placeholders::_1)); 21 | _listener.support(methods::PATCH, std::bind(&MicroserviceController::handlePatch, this, std::placeholders::_1)); 22 | _listener.support(methods::HEAD, std::bind(&MicroserviceController::handleHead, this, std::placeholders::_1)); 23 | 24 | pushCommand(L"inited", endpoint()); 25 | } 26 | 27 | void MicroserviceController::pushCommand(string_t command, string_t options) { 28 | 29 | web::json::value result = web::json::value::object(); 30 | 31 | result[U("command")] = web::json::value::string(command); 32 | result[U("options")] = web::json::value::string(options); 33 | 34 | commands.push_back(ws2s(result.serialize())); 35 | } 36 | 37 | const char* MicroserviceController::getCommand() { 38 | string command; 39 | 40 | if (commands.size() < 1) 41 | return NULL; 42 | 43 | command.append(commands.back()); 44 | commands.pop_back(); 45 | 46 | return command.c_str(); 47 | } 48 | 49 | int MicroserviceController::hasCommands() { 50 | return commands.size() > 0; 51 | } 52 | 53 | 54 | void MicroserviceController::setCommandResponse(const char* command, const char* response) { 55 | commandResponses[command] = response; 56 | } 57 | 58 | void MicroserviceController::setCallback(const char* url, const char* format) { 59 | callback_url.clear(); 60 | callback_format.clear(); 61 | callback_url.append(s2ws(url)); 62 | callback_format.append(s2ws(format)); 63 | } 64 | 65 | void MicroserviceController::setCommandWaitTimeout(int timeout) { 66 | wait_timeout = timeout*1000; 67 | } 68 | 69 | void MicroserviceController::setPath(const char *_path, const char* _url_swagger) { 70 | path_docs.clear(); 71 | path_docs.append(_path); 72 | 73 | url_swagger.clear(); 74 | url_swagger.append(_url_swagger); 75 | } 76 | 77 | int MicroserviceController::onEvent(const char* data) { 78 | 79 | if (callback_url.length() < 1) 80 | return -1; 81 | 82 | Concurrency::task task; 83 | http_client callback_client(callback_url); 84 | 85 | try { 86 | 87 | if (callback_format == L"json") { 88 | 89 | task = callback_client.request(methods::POST, "", data); 90 | } 91 | else { 92 | http_request request(methods::POST); 93 | request.headers().add(L"Content-Type", L"application/x-www-form-urlencoded; charset=UTF-8"); 94 | request.set_body(data); 95 | task = callback_client.request(request); 96 | } 97 | 98 | task.then([](http_response response) { 99 | //ucout << response.to_string(); 100 | if (response.status_code() == status_codes::OK) { 101 | auto body = response.extract_string().get(); 102 | ucout << body << std::endl; 103 | } 104 | }).wait(); 105 | 106 | return 1; 107 | } 108 | catch (const web::http::http_exception &e) { 109 | ucout << e.error_code() << endl; 110 | } 111 | catch (const std::exception & ex) { 112 | ucout << ex.what() << endl; 113 | } 114 | catch (...) { 115 | } 116 | 117 | return -1; 118 | } 119 | 120 | auto MicroserviceController::formatError(int code, const utility::string_t message) { 121 | web::json::value result = web::json::value::object(); 122 | 123 | result[U("message")] = web::json::value::string(message); 124 | result[U("code")] = web::json::value::number(code); 125 | 126 | return result; 127 | } 128 | 129 | auto MicroserviceController::formatError(int code, const char* message) { 130 | wstring msg(message, message + strlen(message)); 131 | 132 | return formatError(code, msg); 133 | } 134 | 135 | auto MicroserviceController::formatErrorRequired(utility::string_t field) { 136 | utility::string_t msg(field); 137 | 138 | msg.append(U(" is required")); 139 | 140 | return formatError(402, msg); 141 | } 142 | 143 | void MicroserviceController::handleGet(http_request message) { 144 | auto response = json::value::object(); 145 | auto path = requestPath(message); 146 | auto params = requestQueryParams(message); 147 | 148 | try { 149 | 150 | if (path.size() < 1) { 151 | string p(path_docs); 152 | p.append("docs.html"); 153 | std::ifstream in(p, ios::in); 154 | 155 | http_response response(status_codes::OK); 156 | response.headers().add(L"Content-Type", L"text/html; charset=UTF-8"); 157 | 158 | std::stringstream buffer; 159 | buffer << in.rdbuf(); 160 | string b = buffer.str(); 161 | in.close(); 162 | 163 | response.set_body(b); 164 | message.reply(response); 165 | 166 | return; 167 | } 168 | 169 | if (path[0] == CMD_SWAGGER) { 170 | string p(path_docs); 171 | p.append("swagger.json"); 172 | std::ifstream in(p, ios::in); 173 | 174 | http_response response(status_codes::OK); 175 | response.headers().add(L"Content-Type", L"text/json; charset=UTF-8"); 176 | 177 | std::stringstream buffer; 178 | buffer << in.rdbuf(); 179 | string b = buffer.str(); 180 | in.close(); 181 | 182 | boost::algorithm::replace_all(b, "localhost:6542", url_swagger); 183 | 184 | response.set_body(b); 185 | 186 | message.reply(response); 187 | 188 | return; 189 | } 190 | 191 | if (!token.empty()) { 192 | if (!message.headers().has(header_names::authorization)) { 193 | message.reply(status_codes::Unauthorized); 194 | return; 195 | } 196 | 197 | auto headers = message.headers(); 198 | 199 | if (headers[header_names::authorization] != token) { 200 | message.reply(status_codes::Unauthorized); 201 | return; 202 | } 203 | } 204 | 205 | web::json::value result = web::json::value::object(); 206 | 207 | result[L"command"] = web::json::value::string(path[0]); 208 | 209 | if (path.size() > 1) { 210 | result[L"id"] = web::json::value::string(path[1]); 211 | } 212 | 213 | for (auto it = params.begin(); it != params.end(); ++it) { 214 | result[it->first] = web::json::value::string(it->second); 215 | } 216 | 217 | string command = ws2s(result.serialize()); 218 | commands.push_back(command); 219 | 220 | DWORD dw1 = GetTickCount(); 221 | 222 | while(dw1 + wait_timeout > GetTickCount()) { 223 | 224 | if (commandResponses.contains(command)) { 225 | message.reply(status_codes::OK, commandResponses[command], "application/json"); 226 | commandResponses.remove(command); 227 | return; 228 | } 229 | 230 | Sleep(1); 231 | } 232 | 233 | throw exception("Failed to get info, timeout"); 234 | } 235 | catch (const FormatException & e) { 236 | message.reply(status_codes::BadRequest, formatError(405, e.what())); 237 | } 238 | catch (const RequiredException & e) { 239 | message.reply(status_codes::BadRequest, formatError(405, e.what())); 240 | } 241 | catch (const json::json_exception & e) { 242 | message.reply(status_codes::BadRequest, formatError(410, e.what())); 243 | ucout << e.what() << endl; 244 | } 245 | catch (const std::exception & ex) { 246 | message.reply(status_codes::BadRequest, formatError(410, ex.what())); 247 | ucout << ex.what() << endl; 248 | } 249 | catch (...) { 250 | message.reply(status_codes::InternalError); 251 | } 252 | } 253 | 254 | void MicroserviceController::handlePost(http_request message) { 255 | auto response = json::value::object(); 256 | 257 | try { 258 | 259 | auto path = requestPath(message); 260 | auto params = requestQueryParams(message); 261 | 262 | ucout << message.to_string() << endl; 263 | 264 | if (path.size() < 1) { 265 | message.reply(status_codes::NotFound); 266 | return; 267 | } 268 | 269 | if (!token.empty()) { 270 | if (!message.headers().has(header_names::authorization)) { 271 | message.reply(status_codes::Unauthorized); 272 | return; 273 | } 274 | 275 | auto headers = message.headers(); 276 | 277 | if (headers[header_names::authorization] != token) { 278 | message.reply(status_codes::Unauthorized); 279 | return; 280 | } 281 | } 282 | 283 | if (path[0] == CMD_SUB) { 284 | callback_url = params[U("callback_url")]; 285 | callback_format = params[U("callback_format")]; 286 | 287 | response[U("message")] = json::value::string(L"Succesfully subscribed"); 288 | response[U("code")] = json::value::number(200); 289 | message.reply(status_codes::OK, response); 290 | 291 | return; 292 | } 293 | 294 | message.extract_utf8string(true).then([=](std::string body) { 295 | 296 | if (body.length() < 1) { 297 | throw exception("POST body is empty"); 298 | } 299 | 300 | std::size_t pos = body.find("}"); 301 | std::string command = body.substr(0, pos); 302 | 303 | command.append(",\"command\":\""); 304 | command.append(ws2s(path[0])); 305 | command.append("\"}"); 306 | 307 | commands.push_back(command); 308 | 309 | for (int i = 0; i < wait_timeout; i++) { 310 | if (commandResponses.contains(command)) { 311 | message.reply(status_codes::OK, commandResponses[command], "application/json"); 312 | commandResponses.remove(command); 313 | return; 314 | } 315 | 316 | Sleep(1); 317 | } 318 | 319 | throw exception("Failed to get info, timeout"); 320 | }).wait(); 321 | 322 | } 323 | catch (const ManagerException & e) { 324 | message.reply(status_codes::BadRequest, formatError(e.code, e.what())); 325 | } 326 | catch (const FormatException & e) { 327 | message.reply(status_codes::BadRequest, formatError(405, e.what())); 328 | } 329 | catch (const RequiredException & e) { 330 | message.reply(status_codes::BadRequest, formatError(405, e.what())); 331 | } 332 | catch (const json::json_exception & e) { 333 | message.reply(status_codes::BadRequest, formatError(410, e.what())); 334 | ucout << e.what() << endl; 335 | } 336 | catch (const std::exception & ex) { 337 | message.reply(status_codes::BadRequest, formatError(410, ex.what())); 338 | ucout << ex.what() << endl; 339 | } 340 | catch (...) { 341 | message.reply(status_codes::InternalError); 342 | } 343 | 344 | } 345 | 346 | void MicroserviceController::handleDelete(http_request message) { 347 | try { 348 | auto path = requestPath(message); 349 | auto params = requestQueryParams(message); 350 | 351 | if (path.size() < 1) { 352 | message.reply(status_codes::NotFound); 353 | return; 354 | } 355 | 356 | } 357 | catch (const ManagerException & e) { 358 | message.reply(status_codes::BadRequest, formatError(e.code, e.what())); 359 | } 360 | catch (const FormatException & e) { 361 | message.reply(status_codes::BadRequest, formatError(405, e.what())); 362 | } 363 | catch (const RequiredException & e) { 364 | message.reply(status_codes::BadRequest, formatError(405, e.what())); 365 | } 366 | catch (const json::json_exception & e) { 367 | message.reply(status_codes::BadRequest, formatError(410, e.what())); 368 | ucout << e.what() << endl; 369 | } 370 | catch (const std::exception & ex) { 371 | message.reply(status_codes::BadRequest, formatError(410, ex.what())); 372 | ucout << ex.what() << endl; 373 | } 374 | catch (...) { 375 | message.reply(status_codes::InternalError); 376 | } 377 | } 378 | 379 | void MicroserviceController::handleHead(http_request message) { 380 | auto response = json::value::object(); 381 | response[U("version")] = json::value::string(U("0.1.1")); 382 | response[U("code")] = json::value::number(200); 383 | message.reply(status_codes::OK, "version"); 384 | } 385 | 386 | void MicroserviceController::handleOptions(http_request message) { 387 | http_response response(status_codes::OK); 388 | response.headers().add(U("Allow"), U("GET, POST, OPTIONS")); 389 | response.headers().add(U("Access-Control-Allow-Origin"), U("*")); 390 | response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, OPTIONS")); 391 | response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type")); 392 | message.reply(response); 393 | } 394 | 395 | void MicroserviceController::handleTrace(http_request message) { 396 | message.reply(status_codes::NotImplemented, responseNotImpl(methods::TRCE)); 397 | } 398 | 399 | void MicroserviceController::handleConnect(http_request message) { 400 | message.reply(status_codes::NotImplemented, responseNotImpl(methods::CONNECT)); 401 | } 402 | 403 | void MicroserviceController::handleMerge(http_request message) { 404 | message.reply(status_codes::NotImplemented, responseNotImpl(methods::MERGE)); 405 | } 406 | 407 | void MicroserviceController::handlePatch(http_request message) { 408 | message.reply(status_codes::NotImplemented, responseNotImpl(methods::MERGE)); 409 | } 410 | 411 | void MicroserviceController::handlePut(http_request message) { 412 | message.reply(status_codes::NotImplemented, responseNotImpl(methods::MERGE)); 413 | } 414 | 415 | json::value MicroserviceController::responseNotImpl(const http::method & method) { 416 | 417 | using namespace json; 418 | 419 | auto response = value::object(); 420 | response[U("serviceName")] = value::string(U("MT4 REST")); 421 | response[U("http_method")] = value::string(method); 422 | 423 | return response; 424 | } 425 | -------------------------------------------------------------------------------- /mt5-rest/microsvc_controller.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include "basic_controller.hpp" 9 | #include "session_manager.hpp" 10 | #include "safe_vector.hpp" 11 | #include "safe_map.hpp" 12 | 13 | using namespace cfx; 14 | using namespace std; 15 | using namespace utility; 16 | using namespace web::http::client; 17 | 18 | static string ws2s(const std::wstring& wstr) { 19 | using convert_typeX = std::codecvt_utf8; 20 | std::wstring_convert converterX; 21 | 22 | return converterX.to_bytes(wstr); 23 | }; 24 | 25 | static wstring s2ws(const std::string& str) { 26 | using convert_typeX = std::codecvt_utf8; 27 | std::wstring_convert converterX; 28 | 29 | return converterX.from_bytes(str); 30 | }; 31 | 32 | class MicroserviceController : public BasicController, Controller { 33 | public: 34 | MicroserviceController() : BasicController() {} 35 | ~MicroserviceController() { 36 | } 37 | void handleGet(http_request message) override; 38 | void handlePut(http_request message) override; 39 | void handlePost(http_request message) override; 40 | void handlePatch(http_request message) override; 41 | void handleDelete(http_request message) override; 42 | void handleHead(http_request message) override; 43 | void handleOptions(http_request message) override; 44 | void handleTrace(http_request message) override; 45 | void handleConnect(http_request message) override; 46 | void handleMerge(http_request message) override; 47 | void initRestOpHandlers() override; 48 | 49 | auto formatError(int code, const utility::string_t message); 50 | auto formatError(int code, const char* message); 51 | auto formatErrorRequired(utility::string_t field); 52 | 53 | const char* getCommand(); 54 | void setCommandResponse(const char* command, const char* reponse); 55 | void pushCommand(string_t command, string_t options); 56 | int hasCommands(); 57 | int onEvent(const char* data); 58 | void setCommandWaitTimeout(int timeout); 59 | void setPath(const char* path, const char* url_swaggger); 60 | void setCallback(const char* url, const char* format); 61 | void setAuthToken(const char* _token) { 62 | token.clear(); 63 | token.append(s2ws(_token)); 64 | }; 65 | 66 | private: 67 | static json::value responseNotImpl(const http::method & method); 68 | SafeVector commands; 69 | SafeMap commandResponses; 70 | string_t callback_url; 71 | string_t callback_format; 72 | int wait_timeout; 73 | string path_docs; 74 | string url_swagger; 75 | string_t token; 76 | }; 77 | -------------------------------------------------------------------------------- /mt5-rest/mt5-rest.def: -------------------------------------------------------------------------------- 1 | LIBRARY "mt5-rest.dll" 2 | EXPORTS 3 | Init 4 | Deinit 5 | SetAuthToken -------------------------------------------------------------------------------- /mt5-rest/mt5-rest.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {7359E8DF-CF85-409D-833B-3B66F8DAC462} 24 | Win32Proj 25 | microservicetutorial 26 | 10.0.17763.0 27 | mt5-rest 28 | 29 | 30 | 31 | Application 32 | true 33 | v141 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v141 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v141 47 | Unicode 48 | 49 | 50 | DynamicLibrary 51 | false 52 | v141 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | false 85 | $(SolutionDir)$(Platform)\$(Configuration)\ 86 | 87 | 88 | 89 | Use 90 | Level3 91 | Disabled 92 | true 93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | false 95 | 96 | 97 | 98 | 99 | Console 100 | true 101 | 102 | 103 | 104 | 105 | Use 106 | Level3 107 | Disabled 108 | true 109 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 110 | false 111 | 112 | 113 | Console 114 | true 115 | 116 | 117 | 118 | 119 | Use 120 | Level3 121 | MaxSpeed 122 | true 123 | true 124 | true 125 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 126 | true 127 | 128 | 129 | Console 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | Use 138 | Level3 139 | MaxSpeed 140 | true 141 | true 142 | true 143 | _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 144 | true 145 | ..\packages\x64-windows\include;..\..\boost_1_69_0;%(AdditionalIncludeDirectories); 146 | Sync 147 | 148 | 149 | Console 150 | true 151 | true 152 | true 153 | ..\packages\x64-windows\lib\;..\..\boost_1_69_0\lib64-msvc-14.1;$(SolutionDir)$(Platform)\$(Configuration); 154 | cpprest_2_10.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 155 | mt5-rest.def 156 | 157 | 158 | taskkill /IM ServiceHub.DataWarehouseHost.exe /F 2>nul 1>nul 159 | Exit 0 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | Create 183 | Create 184 | Create 185 | Create 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /mt5-rest/mt5-rest.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | false 5 | 6 | -------------------------------------------------------------------------------- /mt5-rest/network_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "network_utils.hpp" 3 | 4 | 5 | namespace cfx { 6 | 7 | HostInetInfo NetworkUtils::queryHostInetInfo() { 8 | io_service ios; 9 | tcp::resolver resolver(ios); 10 | tcp::resolver::query query(host_name(), ""); 11 | return resolver.resolve(query); 12 | } 13 | 14 | utility::string_t NetworkUtils::hostIP(unsigned short family) { 15 | auto hostInetInfo = queryHostInetInfo(); 16 | tcp::resolver::iterator end; 17 | while (hostInetInfo != end) { 18 | tcp::endpoint ep = *hostInetInfo++; 19 | sockaddr sa = *ep.data(); 20 | if (sa.sa_family == family) { 21 | return utility::conversions::to_string_t(ep.address().to_string()); 22 | } 23 | } 24 | return nullptr; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /mt5-rest/network_utils.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Mejia on 11/28/16. 3 | // 4 | // MIT License 5 | // 6 | // Copyright (c) 2016 ivmeroLabs. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | 27 | #pragma once 28 | 29 | #include "stdafx.h" 30 | #include 31 | 32 | using namespace boost::asio; 33 | using namespace boost::asio::ip; 34 | 35 | namespace cfx { 36 | 37 | using HostInetInfo = tcp::resolver::iterator; 38 | 39 | class NetworkUtils { 40 | private: 41 | static HostInetInfo queryHostInetInfo(); 42 | static utility::string_t hostIP(unsigned short family); 43 | public: 44 | // gets the host IP4 string formatted 45 | static utility::string_t hostIP4() { 46 | return hostIP(AF_INET); 47 | } 48 | 49 | // gets the host IP6 string formatted 50 | static utility::string_t hostIP6() { 51 | 52 | return hostIP(AF_INET6); 53 | } 54 | static std::string hostName() { 55 | return ip::host_name(); 56 | } 57 | }; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /mt5-rest/safe_map.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include "safe_map.hpp" 5 | 6 | string& SafeMap::operator[](string key) { 7 | return data[key]; 8 | } 9 | 10 | void SafeMap::add(string key, string value) { 11 | lock_guard lock(mut); 12 | data[key] = value; 13 | cond.notify_one(); 14 | } 15 | 16 | bool SafeMap::contains(string key) { 17 | return data.count(key) > 0; 18 | } 19 | 20 | void SafeMap::remove(string key) { 21 | lock_guard lock(mut); 22 | data.erase(key); 23 | cond.notify_one(); 24 | } -------------------------------------------------------------------------------- /mt5-rest/safe_map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SAFEMAP_HPP 2 | #define SAFEMAP_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | class SafeMap { 12 | public: 13 | SafeMap() : data(), mut(), cond() {} 14 | SafeMap(const SafeMap& orig) : data(orig.data), mut(), cond() {} 15 | ~SafeMap() {} 16 | 17 | void add(string key, string value); 18 | string& operator[](const string key); 19 | void remove(string key); 20 | bool contains(string key); 21 | 22 | private: 23 | map data; 24 | mutex mut; 25 | condition_variable cond; 26 | }; 27 | 28 | #endif /* SAFEMAP_HPP */ -------------------------------------------------------------------------------- /mt5-rest/safe_vector.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include "safe_vector.hpp" 5 | 6 | void SafeVector::insert(string in, const int index) 7 | { 8 | lock_guard lock(mut); 9 | vec[index] = move(in); 10 | cond.notify_one(); 11 | } 12 | 13 | void SafeVector::push_back(string in) 14 | { 15 | lock_guard lock(mut); 16 | vec.push_back(move(in)); 17 | cond.notify_one(); 18 | } 19 | 20 | void SafeVector::pop_back() 21 | { 22 | lock_guard lock(mut); 23 | vec.pop_back(); 24 | cond.notify_one(); 25 | } 26 | 27 | string& SafeVector::back() 28 | { 29 | return vec.back(); 30 | } 31 | 32 | size_t SafeVector::size() { 33 | return vec.size(); 34 | } 35 | 36 | string& SafeVector::operator[](const int index) 37 | { 38 | return vec[index]; 39 | } 40 | 41 | vector::iterator SafeVector::begin() 42 | { 43 | return vec.begin(); 44 | } 45 | 46 | vector::iterator SafeVector::end() 47 | { 48 | return vec.end(); 49 | } 50 | 51 | vector SafeVector::toVector() 52 | { 53 | return vec; 54 | } -------------------------------------------------------------------------------- /mt5-rest/safe_vector.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SAFEVECTOR_HPP 2 | #define SAFEVECTOR_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | class SafeVector { 11 | public: 12 | SafeVector() : vec(), mut(), cond() {} 13 | SafeVector(const SafeVector& orig) : vec(orig.vec), mut(), cond() {} 14 | ~SafeVector() {} 15 | 16 | void insert(string in, const int index); 17 | void push_back(string in); 18 | void pop_back(); 19 | size_t size(); 20 | string& operator[](const int index); 21 | string& back(); 22 | vector::iterator begin(); 23 | vector::iterator end(); 24 | vector toVector(); 25 | 26 | private: 27 | vector vec; 28 | mutex mut; 29 | condition_variable cond; 30 | }; 31 | 32 | #endif /* SAFEVECTOR_HPP */ -------------------------------------------------------------------------------- /mt5-rest/session_manager.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "session_manager.hpp" 3 | 4 | ManagersDatabase managerDB; 5 | std::mutex DBMutex; 6 | 7 | utility::string_t SessionManager:: save(const utility::string_t server, const utility::string_t login, const string_t password) { 8 | 9 | std::unique_lock lock{ DBMutex }; 10 | utility::string_t token; 11 | 12 | token.append(login); 13 | 14 | if (managerDB.find(token) != managerDB.end()) { 15 | return token; 16 | } 17 | 18 | ManagerInformation info; 19 | info.server = server; 20 | info.login = login; 21 | info.password = password; 22 | managerDB.insert( 23 | std::pair(token, 24 | info)); 25 | 26 | return token; 27 | } 28 | 29 | bool SessionManager::check( const utility::string_t key, ManagerInformation & info) { 30 | 31 | if (managerDB.find(key) != managerDB.end()) { 32 | auto i = managerDB[key]; 33 | info = i; 34 | return true; 35 | } 36 | 37 | return false; 38 | } -------------------------------------------------------------------------------- /mt5-rest/session_manager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace utility; 8 | 9 | typedef struct { 10 | utility::string_t server; 11 | utility::string_t login; 12 | utility::string_t password; 13 | } ManagerInformation; 14 | 15 | using ManagersDatabase = std::map; 16 | 17 | class SessionManager { 18 | public: 19 | utility::string_t save(const utility::string_t server, const utility::string_t login, const utility::string_t password); 20 | bool check(const utility::string_t key, ManagerInformation & managerInfo); 21 | }; -------------------------------------------------------------------------------- /mt5-rest/std_micro_service.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Mejia on 12/03/16. 3 | // 4 | // MIT License 5 | // 6 | // Copyright (c) 2016 ivmeroLabs. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | 27 | #pragma once 28 | 29 | 30 | -------------------------------------------------------------------------------- /mt5-rest/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/mt5-rest/stdafx.cpp -------------------------------------------------------------------------------- /mt5-rest/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/mt5-rest/stdafx.h -------------------------------------------------------------------------------- /mt5-rest/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikha-dev/mt5-rest/9f286fa1b51a8d9efbfe5e52af2b65cb92cea31b/mt5-rest/targetver.h -------------------------------------------------------------------------------- /mt5-rest/types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | 4 | using namespace std; 5 | using jtype = json::value::value_type; 6 | 7 | class FormatException : public std::exception { 8 | char message[100]; 9 | public: 10 | FormatException(const utility::string_t field, const utility::string_t type) { 11 | utility::string_t t(field); 12 | t.append(L" should be "); 13 | t.append(type); 14 | 15 | size_t i; 16 | wcstombs_s(&i, message, t.length() + 1, t.c_str(), t.length()); 17 | } 18 | const char * what() const throw() { 19 | return message; 20 | } 21 | }; 22 | 23 | class ManagerException : public std::exception { 24 | char description[100]; 25 | 26 | public: 27 | int code; 28 | ManagerException(const int code_, const char * description_) { 29 | code = code_; 30 | strncpy_s(description, description_, 100); 31 | } 32 | 33 | const char * what() const throw() { 34 | return description; 35 | } 36 | 37 | }; 38 | 39 | class RequiredException : public std::exception { 40 | char message[100]; 41 | public: 42 | RequiredException(const utility::string_t field) { 43 | utility::string_t t(field); 44 | t.append(L" is required"); 45 | 46 | size_t i; 47 | wcstombs_s(&i, message, t.length() + 1, t.c_str(), t.length()); 48 | } 49 | const char * what() const throw() { 50 | return message; 51 | } 52 | }; 53 | 54 | struct Error { 55 | utility::string_t description; 56 | int code; 57 | 58 | web::json::value AsJSON() const 59 | { 60 | web::json::value result = web::json::value::object(); 61 | 62 | result[U("descr")] = web::json::value::string(description); 63 | result[U("code")] = web::json::value::number(code); 64 | 65 | return result; 66 | } 67 | }; -------------------------------------------------------------------------------- /mt5-rest/usr_interrupt_handler.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static std::condition_variable _condition; 7 | static std::mutex _mutex; 8 | 9 | namespace cfx { 10 | class InterruptHandler { 11 | public: 12 | static void hookSIGINT() { 13 | signal(SIGINT, handleUserInterrupt); 14 | } 15 | 16 | static void handleUserInterrupt(int signal) { 17 | if (signal == SIGINT) { 18 | std::cout << "SIGINT trapped ..." << '\n'; 19 | _condition.notify_one(); 20 | } 21 | } 22 | 23 | static void waitForUserInterrupt() { 24 | std::unique_lock lock{ _mutex }; 25 | _condition.wait(lock); 26 | std::cout << "user has signaled to interrup program..." << '\n'; 27 | lock.unlock(); 28 | } 29 | }; 30 | } 31 | --------------------------------------------------------------------------------