├── LICENSE ├── MQL4 ├── Experts │ └── hitback │ │ └── hitback.mq4 ├── Include │ ├── Zmq │ │ ├── AtomicCounter.mqh │ │ ├── Common.mqh │ │ ├── Context.mqh │ │ ├── Errno.mqh │ │ ├── Socket.mqh │ │ ├── SocketOptions.mqh │ │ ├── Z85.mqh │ │ ├── Zmq.mqh │ │ └── ZmqMsg.mqh │ ├── hash.mqh │ └── json.mqh ├── Libraries │ ├── libsodium.dll │ └── libzmq.dll └── Scripts │ ├── client.mq4 │ └── server.mq4 ├── MQL5 ├── Experts │ └── hitback │ │ └── hitback.mq5 ├── Include │ ├── Zmq │ │ ├── AtomicCounter.mqh │ │ ├── Common.mqh │ │ ├── Context.mqh │ │ ├── Errno.mqh │ │ ├── Socket.mqh │ │ ├── SocketOptions.mqh │ │ ├── Z85.mqh │ │ ├── Zmq.mqh │ │ └── ZmqMsg.mqh │ ├── hash.mqh │ └── json.mqh ├── Libraries │ ├── libsodium.dll │ └── libzmq.dll └── Scripts │ ├── client.mq5 │ └── server.mq5 ├── README.md └── ZMQ-SERVER ├── .gitignore ├── README ├── app.js ├── config.js ├── consumer-module.js ├── exchanges ├── fxpro.js └── xm.js ├── kafka-module.js ├── mars.js ├── package.json ├── queue.js ├── queueconf.js └── utils.js /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MQL4/Experts/hitback/hitback.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| hitback.mq4 | 3 | //| Copyright 2017, Hitback. | 4 | //| https://www.hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback." 7 | #property link "https://www.hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | 11 | //--- Include a class of the Standard Library 12 | #include 13 | #include 14 | #include 15 | 16 | string currency = Symbol(); 17 | extern string ip_adress = "*"; 18 | extern string prefixPort = "20"; 19 | 20 | // ZMQ 21 | Context context; 22 | Socket socket(context,ZMQ_PUB); 23 | 24 | //+------------------------------------------------------------------+ 25 | //| Expert initialization function | 26 | //+------------------------------------------------------------------+ 27 | int OnInit() 28 | { 29 | 30 | MarketBookAdd(currency); 31 | 32 | // Print("using zeromq version "+getVersion()); 33 | if( socket.bind("tcp://"+serverAdress( currency )) ) 34 | { 35 | Print("Problem with ZMQ bind " + "tcp://"+serverAdress( currency )); 36 | }else{ 37 | Print("ZMQ bind " + "tcp://"+serverAdress( currency ) + " Connected"); 38 | } 39 | 40 | return(INIT_SUCCEEDED); 41 | } 42 | //+------------------------------------------------------------------+ 43 | //| Expert deinitialization function | 44 | //+------------------------------------------------------------------+ 45 | void OnDeinit(const int reason) 46 | { 47 | //--- close the DOM 48 | if(!MarketBookRelease(currency)) 49 | Print("Failed to close the DOM!"); 50 | } 51 | 52 | string serverAdress(string symbol_received) 53 | { 54 | string str = ""; 55 | 56 | if( "AUDCAD" == symbol_received ) { 57 | str=ip_adress+":"+prefixPort+"02"; 58 | return str; 59 | } 60 | 61 | if( "AUDCHF" == symbol_received ) { 62 | str=ip_adress+":"+prefixPort+"03"; 63 | return str; 64 | } 65 | 66 | if( "EURUSD" == symbol_received ) { 67 | str=ip_adress+":"+prefixPort+"04"; 68 | return str; 69 | } 70 | 71 | if( "AUDJPY" == symbol_received ) { 72 | str=ip_adress+":"+prefixPort+"05"; 73 | return str; 74 | } 75 | 76 | if( "AUDNZD" == symbol_received ) { 77 | str=ip_adress+":"+prefixPort+"06"; 78 | return str; 79 | } 80 | 81 | if( "CADCHF" == symbol_received ) { 82 | str=ip_adress+":"+prefixPort+"07"; 83 | return str; 84 | } 85 | 86 | if( "CADJPY" == symbol_received ) { 87 | str=ip_adress+":"+prefixPort+"08"; 88 | return str; 89 | } 90 | 91 | if( "CHFJPY" == symbol_received ) { 92 | str=ip_adress+":"+prefixPort+"09"; 93 | return str; 94 | } 95 | 96 | if( "EURAUD" == symbol_received ) { 97 | str=ip_adress+":"+prefixPort+"10"; 98 | return str; 99 | } 100 | 101 | if( "EURCAD" == symbol_received ) { 102 | str=ip_adress+":"+prefixPort+"11"; 103 | return str; 104 | } 105 | 106 | if( "EURCHF" == symbol_received ) { 107 | str=ip_adress+":"+prefixPort+"12"; 108 | return str; 109 | } 110 | 111 | if( "EURGBP" == symbol_received ) { 112 | str=ip_adress+":"+prefixPort+"13"; 113 | return str; 114 | } 115 | 116 | if( "GBPAUD" == symbol_received ) { 117 | str=ip_adress+":"+prefixPort+"14"; 118 | return str; 119 | } 120 | 121 | if( "GBPCAD" == symbol_received ) { 122 | str=ip_adress+":"+prefixPort+"15"; 123 | return str; 124 | } 125 | 126 | if( "GBPCHF" == symbol_received ) { 127 | str=ip_adress+":"+prefixPort+"16"; 128 | return str; 129 | } 130 | 131 | if( "GBPJPY" == symbol_received ) { 132 | str=ip_adress+":"+prefixPort+"17"; 133 | return str; 134 | } 135 | 136 | if( "GBPNZD" == symbol_received ) { 137 | str=ip_adress+":"+prefixPort+"18"; 138 | return str; 139 | } 140 | 141 | if( "NZDCHF" == symbol_received ) { 142 | str=ip_adress+":"+prefixPort+"19"; 143 | return str; 144 | } 145 | 146 | if( "NZDJPY" == symbol_received ) { 147 | str=ip_adress+":"+prefixPort+"20"; 148 | return str; 149 | } 150 | 151 | if( "NZDUSD" == symbol_received ) { 152 | str=ip_adress+":"+prefixPort+"21"; 153 | return str; 154 | } 155 | 156 | if( "EURNZD" == symbol_received) { 157 | str=ip_adress+":"+prefixPort+"22"; 158 | return str; 159 | } 160 | 161 | if( "USDCAD" == symbol_received ) { 162 | str=ip_adress+":"+prefixPort+"23"; 163 | return str; 164 | } 165 | 166 | if( "EURJPY" == symbol_received ) { 167 | str=ip_adress+":"+prefixPort+"24"; 168 | return str; 169 | } 170 | 171 | if( "AUDUSD" == symbol_received ) { 172 | str=ip_adress+":"+prefixPort+"25"; 173 | return str; 174 | } 175 | 176 | if( "GBPUSD" == symbol_received ) { 177 | str=ip_adress+":"+prefixPort+"26"; 178 | return str; 179 | } 180 | 181 | if( "USDCHF" == symbol_received ) { 182 | str=ip_adress+":"+prefixPort+"27"; 183 | return str; 184 | } 185 | 186 | if( "USDJPY" == symbol_received ) { 187 | str=ip_adress+":"+prefixPort+"28"; 188 | return str; 189 | } 190 | 191 | return(str); 192 | 193 | } 194 | //+------------------------------------------------------------------+ 195 | //| BookEvent function | 196 | //+------------------------------------------------------------------+ 197 | void OnBookEvent(const string &symbol) 198 | { 199 | // Print("Book event for: "+symbol); 200 | //--- select the symbol 201 | if(symbol==_Symbol) 202 | { 203 | //--- array of the DOM structures 204 | MqlBookInfo last_bookArray[]; 205 | 206 | 207 | //--- get the book 208 | if(MarketBookGet(_Symbol,last_bookArray)) 209 | { 210 | 211 | JSONArray* jaTicks = new JSONArray(); 212 | 213 | //--- process book data 214 | for(int idx=0;idx>> DEBUG: In ",__FUNCTION__,"(",__FILE__,":",__LINE__,") [", msg, "]") 114 | #else 115 | #define Debug(msg) 116 | #endif 117 | //+------------------------------------------------------------------+ 118 | -------------------------------------------------------------------------------- /MQL4/Include/Zmq/Context.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Context.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #include "Common.mqh" 10 | #include "SocketOptions.mqh" 11 | 12 | //--- Context options 13 | #define ZMQ_IO_THREADS 1 14 | #define ZMQ_MAX_SOCKETS 2 15 | #define ZMQ_SOCKET_LIMIT 3 16 | #define ZMQ_THREAD_PRIORITY 3 17 | #define ZMQ_THREAD_SCHED_POLICY 4 18 | #define ZMQ_MAX_MSGSZ 5 19 | 20 | //--- Default for new contexts 21 | #define ZMQ_IO_THREADS_DFLT 1 22 | #define ZMQ_MAX_SOCKETS_DFLT 1023 23 | #define ZMQ_THREAD_PRIORITY_DFLT -1 24 | #define ZMQ_THREAD_SCHED_POLICY_DFLT -1 25 | 26 | #import "libzmq.dll" 27 | intptr_t zmq_ctx_new(void); 28 | int zmq_ctx_term(intptr_t context); 29 | int zmq_ctx_shutdown(intptr_t context); 30 | int zmq_ctx_set(intptr_t context,int option,int optval); 31 | int zmq_ctx_get(intptr_t context,int option); 32 | #import 33 | //+------------------------------------------------------------------+ 34 | //| Wraps a 0MZ context | 35 | //+------------------------------------------------------------------+ 36 | class Context 37 | { 38 | private: 39 | intptr_t m_ref; 40 | protected: 41 | int get(int option) {return zmq_ctx_get(m_ref,option);} 42 | bool set(int option,int optval) {return 0==zmq_ctx_set(m_ref,option,optval);} 43 | public: 44 | Context() {m_ref=zmq_ctx_new();} 45 | ~Context() {if(0!=zmq_ctx_term(m_ref)){Debug("failed to terminate context");}} 46 | // for better cooperation between objects 47 | intptr_t ref() const {return m_ref;} 48 | bool shutdown() {return 0==zmq_ctx_shutdown(m_ref);} 49 | 50 | int getIoThreads() {return get(ZMQ_IO_THREADS);} 51 | void setIoThreads(int value) {if(!set(ZMQ_IO_THREADS,value)){Debug("failed to set ZMQ_IO_THREADS");}} 52 | 53 | int getMaxSockets() {return get(ZMQ_MAX_SOCKETS);} 54 | void setMaxSockets(int value) {if(!set(ZMQ_MAX_SOCKETS,value)){Debug("failed to set ZMQ_MAX_SOCKETS");}} 55 | 56 | int getMaxMessageSize() {return get(ZMQ_MAX_MSGSZ);} 57 | void setMaxMessageSize(int value) {if(!set(ZMQ_MAX_MSGSZ,value)){Debug("failed to set ZMQ_MAX_MSGSZ");}} 58 | 59 | int getSocketLimit() {return get(ZMQ_SOCKET_LIMIT);} 60 | 61 | int getIpv6Options() {return get(ZMQ_IPV6);} 62 | void setIpv6Options(int value) {if(!set(ZMQ_IPV6,value)){Debug("failed to set ZMQ_IPV6");}} 63 | 64 | bool isBlocky() {return 1==get(ZMQ_BLOCKY);} 65 | void setBlocky(bool value) {if(!set(ZMQ_BLOCKY,value?1:0)){Debug("failed to set ZMQ_BLOCKY");}} 66 | 67 | //--- Following options is not supported on windows 68 | void setSchedulingPolicy(int value) {/*ZMQ_THREAD_SCHED_POLICY*/} 69 | void setThreadPriority(int value) {/*ZMQ_THREAD_PRIORITY*/} 70 | }; 71 | //+------------------------------------------------------------------+ 72 | -------------------------------------------------------------------------------- /MQL4/Include/Zmq/Errno.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Errno.mqh | 3 | //+------------------------------------------------------------------+ 4 | 5 | // Following error codes come from Microsoft CRT header errno.h 6 | 7 | // Error codes 8 | #define EPERM 1 9 | #define ENOENT 2 10 | #define ESRCH 3 11 | #define EINTR 4 12 | #define EIO 5 13 | #define ENXIO 6 14 | #define E2BIG 7 15 | #define ENOEXEC 8 16 | #define EBADF 9 17 | #define ECHILD 10 18 | #define EAGAIN 11 19 | #define ENOMEM 12 20 | #define EACCES 13 21 | #define EFAULT 14 22 | #define EBUSY 16 23 | #define EEXIST 17 24 | #define EXDEV 18 25 | #define ENODEV 19 26 | #define ENOTDIR 20 27 | #define EISDIR 21 28 | #define ENFILE 23 29 | #define EMFILE 24 30 | #define ENOTTY 25 31 | #define EFBIG 27 32 | #define ENOSPC 28 33 | #define ESPIPE 29 34 | #define EROFS 30 35 | #define EMLINK 31 36 | #define EPIPE 32 37 | #define EDOM 33 38 | #define EDEADLK 36 39 | #define ENAMETOOLONG 38 40 | #define ENOLCK 39 41 | #define ENOSYS 40 42 | #define ENOTEMPTY 41 43 | 44 | // Error codes used in the Secure CRT functions 45 | #define EINVAL 22 46 | #define ERANGE 34 47 | #define EILSEQ 42 48 | #define STRUNCATE 80 49 | 50 | // Support EDEADLOCK for compatibility with older Microsoft C versions 51 | #define EDEADLOCK EDEADLK 52 | 53 | // POSIX Supplement 54 | #define EALREADY 103 55 | #define EBADMSG 104 56 | #define ECANCELED 105 57 | #define EDESTADDRREQ 109 58 | #define EIDRM 111 59 | #define EISCONN 113 60 | #define ELOOP 114 61 | #define ENODATA 120 62 | #define ENOLINK 121 63 | #define ENOMSG 122 64 | #define ENOPROTOOPT 123 65 | #define ENOSR 124 66 | #define ENOSTR 125 67 | #define ENOTRECOVERABLE 127 68 | #define EOPNOTSUPP 130 69 | #define EOTHER 131 70 | #define EOVERFLOW 132 71 | #define EOWNERDEAD 133 72 | #define EPROTO 134 73 | #define EPROTOTYPE 136 74 | #define ETIME 137 75 | #define ETXTBSY 139 76 | #define EWOULDBLOCK 140 77 | 78 | // Following error codes come from zmq.h 79 | // 0MQ errors 80 | #define ZMQ_HAUSNUMERO 156384712 81 | 82 | #define ENOTSUP (ZMQ_HAUSNUMERO + 1) 83 | #define EPROTONOSUPPORT (ZMQ_HAUSNUMERO + 2) 84 | #define ENOBUFS (ZMQ_HAUSNUMERO + 3) 85 | #define ENETDOWN (ZMQ_HAUSNUMERO + 4) 86 | #define EADDRINUSE (ZMQ_HAUSNUMERO + 5) 87 | #define EADDRNOTAVAIL (ZMQ_HAUSNUMERO + 6) 88 | #define ECONNREFUSED (ZMQ_HAUSNUMERO + 7) 89 | #define EINPROGRESS (ZMQ_HAUSNUMERO + 8) 90 | #define ENOTSOCK (ZMQ_HAUSNUMERO + 9) 91 | #define EMSGSIZE (ZMQ_HAUSNUMERO + 10) 92 | #define EAFNOSUPPORT (ZMQ_HAUSNUMERO + 11) 93 | #define ENETUNREACH (ZMQ_HAUSNUMERO + 12) 94 | #define ECONNABORTED (ZMQ_HAUSNUMERO + 13) 95 | #define ECONNRESET (ZMQ_HAUSNUMERO + 14) 96 | #define ENOTCONN (ZMQ_HAUSNUMERO + 15) 97 | #define ETIMEDOUT (ZMQ_HAUSNUMERO + 16) 98 | #define EHOSTUNREACH (ZMQ_HAUSNUMERO + 17) 99 | #define ENETRESET (ZMQ_HAUSNUMERO + 18) 100 | 101 | // Native 0MQ error codes 102 | #define EFSM (ZMQ_HAUSNUMERO + 51) 103 | #define ENOCOMPATPROTO (ZMQ_HAUSNUMERO + 52) 104 | #define ETERM (ZMQ_HAUSNUMERO + 53) 105 | #define EMTHREAD (ZMQ_HAUSNUMERO + 54) 106 | //+------------------------------------------------------------------+ 107 | -------------------------------------------------------------------------------- /MQL4/Include/Zmq/Socket.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Socket.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | 11 | #include "Common.mqh" 12 | #include "Context.mqh" 13 | #include "SocketOptions.mqh" 14 | #include "ZmqMsg.mqh" 15 | //--- fd is SOCKET on Win32, which is defined as UINT_PTR 16 | struct zmq_pollitem_t 17 | { 18 | intptr_t socket; 19 | uintptr_t fd; 20 | short events; 21 | short revents; 22 | }; 23 | 24 | //--- Socket types 25 | #define ZMQ_PAIR 0 26 | #define ZMQ_PUB 1 27 | #define ZMQ_SUB 2 28 | #define ZMQ_REQ 3 29 | #define ZMQ_REP 4 30 | #define ZMQ_DEALER 5 31 | #define ZMQ_ROUTER 6 32 | #define ZMQ_PULL 7 33 | #define ZMQ_PUSH 8 34 | #define ZMQ_XPUB 9 35 | #define ZMQ_XSUB 10 36 | #define ZMQ_STREAM 11 37 | 38 | //--- Message options 39 | #define ZMQ_MORE 1 40 | #define ZMQ_SRCFD 2 // Deprecated 41 | #define ZMQ_SHARED 3 42 | 43 | //--- Send/recv options 44 | #define ZMQ_DONTWAIT 1 45 | #define ZMQ_SNDMORE 2 46 | 47 | //--- Socket transport events (TCP, IPC and TIPC only) 48 | #define ZMQ_EVENT_CONNECTED 0x0001 49 | #define ZMQ_EVENT_CONNECT_DELAYED 0x0002 50 | #define ZMQ_EVENT_CONNECT_RETRIED 0x0004 51 | #define ZMQ_EVENT_LISTENING 0x0008 52 | #define ZMQ_EVENT_BIND_FAILED 0x0010 53 | #define ZMQ_EVENT_ACCEPTED 0x0020 54 | #define ZMQ_EVENT_ACCEPT_FAILED 0x0040 55 | #define ZMQ_EVENT_CLOSED 0x0080 56 | #define ZMQ_EVENT_CLOSE_FAILED 0x0100 57 | #define ZMQ_EVENT_DISCONNECTED 0x0200 58 | #define ZMQ_EVENT_MONITOR_STOPPED 0x0400 59 | #define ZMQ_EVENT_ALL 0xFFFF 60 | 61 | //--- I/O multiplexing 62 | #define ZMQ_POLLIN 1 63 | #define ZMQ_POLLOUT 2 64 | // We only use 0MQ sockets on Windows 65 | // So POLLERR and POLLPRI is of no use 66 | #define ZMQ_POLLERR 4 67 | #define ZMQ_POLLPRI 8 68 | 69 | #define ZMQ_POLLITEMS_DFLT 16 70 | 71 | #import "libzmq.dll" 72 | //+------------------------------------------------------------------+ 73 | //| Sockets | 74 | //+------------------------------------------------------------------+ 75 | intptr_t zmq_socket(intptr_t context,int type); 76 | int zmq_close(intptr_t s); 77 | int zmq_bind(intptr_t s,const char &addr[]); 78 | int zmq_connect(intptr_t s,const char &addr[]); 79 | int zmq_unbind(intptr_t s,const char &addr[]); 80 | int zmq_disconnect(intptr_t s,const char &addr[]); 81 | int zmq_send(intptr_t s,const uchar &buf[],size_t len,int flags); 82 | int zmq_send_const(intptr_t s,const uchar &buf[],size_t len,int flags); 83 | int zmq_recv(intptr_t s,uchar &buf[],size_t len,int flags); 84 | int zmq_socket_monitor(intptr_t s,const char &addr[],int events); 85 | //+------------------------------------------------------------------+ 86 | //| Message | 87 | //+------------------------------------------------------------------+ 88 | int zmq_msg_send(zmq_msg_t &msg,intptr_t s,int flags); 89 | int zmq_msg_recv(zmq_msg_t &msg,intptr_t s,int flags); 90 | //+------------------------------------------------------------------+ 91 | //| I/O multiplexing | 92 | //+------------------------------------------------------------------+ 93 | int zmq_poll(zmq_pollitem_t &items[],int nitems,long timeout); 94 | //+------------------------------------------------------------------+ 95 | //| Message proxying | 96 | //+------------------------------------------------------------------+ 97 | int zmq_proxy(intptr_t frontend_ref,intptr_t backend_ref,intptr_t capture_ref); 98 | int zmq_proxy_steerable(intptr_t frontend_ref,intptr_t backend_ref,intptr_t capture_ref,intptr_t control_ref); 99 | #import 100 | //+------------------------------------------------------------------+ 101 | //| Wraps a 0MQ socket | 102 | //+------------------------------------------------------------------+ 103 | class Socket: public SocketOptions 104 | { 105 | public: 106 | //--- it is not recommended to use this constructor directly: use Context factory methods instead 107 | Socket(const Context &ctx,int type):SocketOptions(zmq_socket(ctx.ref(),type)){} 108 | virtual ~Socket() {if(0!=zmq_close(m_ref)){Debug(StringFormat("Failed to close socket 0x%0X",m_ref));}} 109 | 110 | // for better cooperation between objects 111 | intptr_t ref() const {return m_ref;} 112 | 113 | bool valid() const {return m_ref!=0;} 114 | 115 | //--- see Zmq::error() if any of the following command failed 116 | //--- connection management 117 | bool bind(string addr); 118 | bool unbind(string addr); 119 | bool connect(string addr); 120 | bool disconnect(string addr); 121 | 122 | //--- send and receive packets 123 | bool recv(uchar &buf[],bool nowait=false); 124 | bool send(const uchar &buf[],bool nowait=false,bool more=false); 125 | bool sendConst(const uchar &buf[],bool nowait=false,bool more=false); 126 | 127 | bool send(ZmqMsg &msg,bool nowait=false,bool more=false); 128 | string recv(ZmqMsg &msg,bool nowait=false); 129 | 130 | void register(zmq_pollitem_t &pollitem,bool read=false,bool write=false); 131 | void register(zmq_pollitem_t &pollitems[],int index,bool read=false,bool write=false); 132 | 133 | //--- monitor socket events 134 | bool monitor(string addr,int events); 135 | 136 | //--- proxy 137 | static bool proxy(Socket *frontend,Socket *backend,Socket *capture); 138 | static bool proxySteerable(Socket *frontend,Socket *backend,Socket *capture,Socket *control); 139 | 140 | //--- poll 141 | static int poll(zmq_pollitem_t &arr[],long timeout); 142 | }; 143 | //+------------------------------------------------------------------+ 144 | //| | 145 | //+------------------------------------------------------------------+ 146 | bool Socket::bind(string addr) 147 | { 148 | char arr[]; 149 | StringToUtf8(addr,arr); 150 | bool res=(0==zmq_bind(m_ref,arr)); 151 | ArrayFree(arr); 152 | return res; 153 | } 154 | //+------------------------------------------------------------------+ 155 | //| | 156 | //+------------------------------------------------------------------+ 157 | bool Socket::unbind(string addr) 158 | { 159 | char arr[]; 160 | StringToUtf8(addr,arr); 161 | bool res=(0==zmq_unbind(m_ref,arr)); 162 | ArrayFree(arr); 163 | return res; 164 | } 165 | //+------------------------------------------------------------------+ 166 | //| | 167 | //+------------------------------------------------------------------+ 168 | bool Socket::connect(string addr) 169 | { 170 | char arr[]; 171 | StringToUtf8(addr,arr); 172 | bool res=(0==zmq_connect(m_ref,arr)); 173 | ArrayFree(arr); 174 | return res; 175 | } 176 | //+------------------------------------------------------------------+ 177 | //| | 178 | //+------------------------------------------------------------------+ 179 | bool Socket::disconnect(string addr) 180 | { 181 | char arr[]; 182 | StringToUtf8(addr,arr); 183 | bool res=(0==zmq_disconnect(m_ref,arr)); 184 | ArrayFree(arr); 185 | return res; 186 | } 187 | //+------------------------------------------------------------------+ 188 | //| | 189 | //+------------------------------------------------------------------+ 190 | bool Socket::recv(uchar &buf[],bool nowait=false) 191 | { 192 | Print("recv func 1"); 193 | int options=0; 194 | if(nowait) options|=ZMQ_DONTWAIT; 195 | return 0==zmq_recv(m_ref,buf,ArraySize(buf),options); 196 | } 197 | //+------------------------------------------------------------------+ 198 | //| | 199 | //+------------------------------------------------------------------+ 200 | bool Socket::send(const uchar &buf[],bool nowait=false,bool more=false) 201 | { 202 | int options=0; 203 | if(nowait) options|=ZMQ_DONTWAIT; 204 | if(more) options|=ZMQ_SNDMORE; 205 | return 0==zmq_send(m_ref,buf,ArraySize(buf),options); 206 | } 207 | //+------------------------------------------------------------------+ 208 | //| | 209 | //+------------------------------------------------------------------+ 210 | bool Socket::sendConst(const uchar &buf[],bool nowait=false,bool more=false) 211 | { 212 | int options=0; 213 | if(nowait) options|=ZMQ_DONTWAIT; 214 | if(more) options|=ZMQ_SNDMORE; 215 | return 0==zmq_send_const(m_ref,buf,ArraySize(buf),options); 216 | } 217 | //+------------------------------------------------------------------+ 218 | //| Send a zmq_msg_t through a socket | 219 | //+------------------------------------------------------------------+ 220 | bool Socket::send(ZmqMsg &msg,bool nowait=false,bool more=false) 221 | { 222 | int flags=0; 223 | if(nowait) flags|=ZMQ_DONTWAIT; 224 | if(more) flags|=ZMQ_SNDMORE; 225 | return -1!=zmq_msg_send(msg,m_ref,flags); 226 | } 227 | 228 | string Socket::recv(ZmqMsg &msg,bool nowait=false) 229 | { 230 | 231 | int flags=0; 232 | string message = ""; 233 | if(nowait) flags|=ZMQ_DONTWAIT; 234 | 235 | if( zmq_msg_recv(msg,m_ref,flags) ) { 236 | message = _ptr2str(zmq_msg_data(msg)); 237 | } 238 | return message; 239 | } 240 | 241 | //+------------------------------------------------------------------+ 242 | //| | 243 | //+------------------------------------------------------------------+ 244 | bool Socket::monitor(string addr,int events) 245 | { 246 | uchar str[]; 247 | StringToUtf8(addr,str); 248 | bool res=(0==zmq_socket_monitor(m_ref,str,events)); 249 | ArrayFree(str); 250 | return res; 251 | } 252 | //+------------------------------------------------------------------+ 253 | //| | 254 | //+------------------------------------------------------------------+ 255 | void Socket::register(zmq_pollitem_t &pollitem,bool read=false,bool write=false) 256 | { 257 | ZeroMemory(pollitem); 258 | pollitem.socket=m_ref; 259 | if(read) pollitem.events|=ZMQ_POLLIN; 260 | if(write) pollitem.events|=ZMQ_POLLOUT; 261 | } 262 | //+------------------------------------------------------------------+ 263 | //| | 264 | //+------------------------------------------------------------------+ 265 | void Socket::register(zmq_pollitem_t &pollitems[],int index,bool read=false,bool write=false) 266 | { 267 | ZeroMemory(pollitems[index]); 268 | pollitems[index].socket=m_ref; 269 | if(read) pollitems[index].events|=ZMQ_POLLIN; 270 | if(write) pollitems[index].events|=ZMQ_POLLOUT; 271 | } 272 | //+------------------------------------------------------------------+ 273 | //| | 274 | //+------------------------------------------------------------------+ 275 | bool Socket::proxy(Socket *frontend,Socket *backend,Socket *capture) 276 | { 277 | intptr_t frontend_ref= CheckPointer(frontend)==POINTER_DYNAMIC?frontend.ref():0; 278 | intptr_t backend_ref = CheckPointer(backend)==POINTER_DYNAMIC?backend.ref():0; 279 | intptr_t capture_ref=CheckPointer(capture)==POINTER_DYNAMIC?capture.ref():0; 280 | return 0==zmq_proxy(frontend_ref, backend_ref, capture_ref); 281 | } 282 | //+------------------------------------------------------------------+ 283 | //| | 284 | //+------------------------------------------------------------------+ 285 | bool Socket::proxySteerable(Socket *frontend,Socket *backend,Socket *capture,Socket *control) 286 | { 287 | intptr_t frontend_ref= CheckPointer(frontend)==POINTER_DYNAMIC?frontend.ref():0; 288 | intptr_t backend_ref = CheckPointer(backend)==POINTER_DYNAMIC?backend.ref():0; 289 | intptr_t capture_ref=CheckPointer(capture)==POINTER_DYNAMIC?capture.ref():0; 290 | intptr_t control_ref=CheckPointer(control)==POINTER_DYNAMIC?control.ref():0; 291 | return 0==zmq_proxy_steerable(frontend_ref, backend_ref, capture_ref, control_ref); 292 | } 293 | //+------------------------------------------------------------------+ 294 | //| | 295 | //+------------------------------------------------------------------+ 296 | int Socket::poll(zmq_pollitem_t &arr[],long timeout) 297 | { 298 | return zmq_poll(arr,ArraySize(arr),timeout); 299 | } 300 | //+------------------------------------------------------------------+ 301 | 302 | //+------------------------------------------------------------------+ 303 | //| Receive a zmq_msg_t from a socket | 304 | //+------------------------------------------------------------------+ 305 | #import "kernel32.dll" 306 | int lstrlenA(int); 307 | void RtlMoveMemory(uchar & arr[], int, int); 308 | int LocalFree(int); // May need to be changed depending on how the DLL allocates memory 309 | #import 310 | 311 | string _ptr2str(int recvPtr) { 312 | // Get the length of the string 313 | int mssgLen = lstrlenA(recvPtr); 314 | // if message length is 0, leave. 315 | if(mssgLen<1){ 316 | return(""); 317 | } 318 | //else z_trace("mssgLen: "+mssgLen); 319 | // Create a uchar[] array whose size is the string length (plus null terminator) 320 | uchar stringChar[]; 321 | ArrayResize(stringChar, mssgLen+1); 322 | 323 | // Use the Win32 API to copy the string from the block returned by the DLL 324 | // into the uchar[] array 325 | RtlMoveMemory(stringChar, recvPtr, mssgLen+1); 326 | // Convert the uchar[] array to a message string 327 | string mssg = CharArrayToString(stringChar); 328 | // Free the string memory returned by the DLL. This step can be removed but, without it, 329 | // there will be a memory leak. 330 | // The correct method for freeing the string *depends on how the DLL allocated the memory* 331 | // The following assumes that the DLL has used LocalAlloc (or an indirect equivalent). If not, 332 | // then the following line may not fix the leak, and may even cause a crash. 333 | //LocalFree(recvPtr); 334 | return mssg; 335 | } -------------------------------------------------------------------------------- /MQL4/Include/Zmq/SocketOptions.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Socket.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | 11 | #include "Common.mqh" 12 | 13 | #import "libzmq.dll" 14 | // We can overload the same function for different data types 15 | // as in the C level the optval paramter is just a pointer 16 | #define SOCKOPT_OVERLOAD_ARRAY(TYPE) \ 17 | int zmq_setsockopt(intptr_t s,int option,const TYPE &optval[],\ 18 | size_t optvallen);\ 19 | int zmq_getsockopt(intptr_t s,int option,TYPE &optval[],\ 20 | size_t &optvallen);\ 21 | 22 | #define SOCKOPT_OVERLOAD(TYPE) \ 23 | int zmq_setsockopt(intptr_t s,int option,const TYPE &optval,\ 24 | size_t optvallen);\ 25 | int zmq_getsockopt(intptr_t s,int option,TYPE &optval,\ 26 | size_t &optvallen);\ 27 | 28 | SOCKOPT_OVERLOAD_ARRAY(uchar) 29 | SOCKOPT_OVERLOAD(long) 30 | SOCKOPT_OVERLOAD(ulong) 31 | SOCKOPT_OVERLOAD(int) 32 | SOCKOPT_OVERLOAD(uint) 33 | #import 34 | 35 | // Socket options 36 | #define ZMQ_AFFINITY 4 37 | #define ZMQ_IDENTITY 5 38 | #define ZMQ_SUBSCRIBE 6 39 | #define ZMQ_UNSUBSCRIBE 7 40 | #define ZMQ_RATE 8 41 | #define ZMQ_RECOVERY_IVL 9 42 | #define ZMQ_SNDBUF 11 43 | #define ZMQ_RCVBUF 12 44 | #define ZMQ_RCVMORE 13 45 | #define ZMQ_FD 14 46 | #define ZMQ_EVENTS 15 47 | #define ZMQ_TYPE 16 48 | #define ZMQ_LINGER 17 49 | #define ZMQ_RECONNECT_IVL 18 50 | #define ZMQ_BACKLOG 19 51 | #define ZMQ_RECONNECT_IVL_MAX 21 52 | #define ZMQ_MAXMSGSIZE 22 53 | #define ZMQ_SNDHWM 23 54 | #define ZMQ_RCVHWM 24 55 | #define ZMQ_MULTICAST_HOPS 25 56 | #define ZMQ_RCVTIMEO 27 57 | #define ZMQ_SNDTIMEO 28 58 | #define ZMQ_LAST_ENDPOINT 32 59 | #define ZMQ_ROUTER_MANDATORY 33 60 | #define ZMQ_TCP_KEEPALIVE 34 61 | #define ZMQ_TCP_KEEPALIVE_CNT 35 62 | #define ZMQ_TCP_KEEPALIVE_IDLE 36 63 | #define ZMQ_TCP_KEEPALIVE_INTVL 37 64 | #define ZMQ_IMMEDIATE 39 65 | #define ZMQ_XPUB_VERBOSE 40 66 | #define ZMQ_ROUTER_RAW 41 67 | #define ZMQ_IPV6 42 68 | #define ZMQ_MECHANISM 43 69 | #define ZMQ_PLAIN_SERVER 44 70 | #define ZMQ_PLAIN_USERNAME 45 71 | #define ZMQ_PLAIN_PASSWORD 46 72 | #define ZMQ_CURVE_SERVER 47 73 | #define ZMQ_CURVE_PUBLICKEY 48 74 | #define ZMQ_CURVE_SECRETKEY 49 75 | #define ZMQ_CURVE_SERVERKEY 50 76 | #define ZMQ_PROBE_ROUTER 51 77 | #define ZMQ_REQ_CORRELATE 52 78 | #define ZMQ_REQ_RELAXED 53 79 | #define ZMQ_CONFLATE 54 80 | #define ZMQ_ZAP_DOMAIN 55 81 | #define ZMQ_ROUTER_HANDOVER 56 82 | #define ZMQ_TOS 57 83 | #define ZMQ_CONNECT_RID 61 84 | #define ZMQ_GSSAPI_SERVER 62 85 | #define ZMQ_GSSAPI_PRINCIPAL 63 86 | #define ZMQ_GSSAPI_SERVICE_PRINCIPAL 64 87 | #define ZMQ_GSSAPI_PLAINTEXT 65 88 | #define ZMQ_HANDSHAKE_IVL 66 89 | #define ZMQ_SOCKS_PROXY 68 90 | #define ZMQ_XPUB_NODROP 69 91 | #define ZMQ_BLOCKY 70 92 | #define ZMQ_XPUB_MANUAL 71 93 | #define ZMQ_XPUB_WELCOME_MSG 72 94 | #define ZMQ_STREAM_NOTIFY 73 95 | #define ZMQ_INVERT_MATCHING 74 96 | #define ZMQ_HEARTBEAT_IVL 75 97 | #define ZMQ_HEARTBEAT_TTL 76 98 | #define ZMQ_HEARTBEAT_TIMEOUT 77 99 | #define ZMQ_XPUB_VERBOSER 78 100 | #define ZMQ_CONNECT_TIMEOUT 79 101 | #define ZMQ_TCP_MAXRT 80 102 | #define ZMQ_THREAD_SAFE 81 103 | #define ZMQ_MULTICAST_MAXTPDU 84 104 | #define ZMQ_VMCI_BUFFER_SIZE 85 105 | #define ZMQ_VMCI_BUFFER_MIN_SIZE 86 106 | #define ZMQ_VMCI_BUFFER_MAX_SIZE 87 107 | #define ZMQ_VMCI_CONNECT_TIMEOUT 88 108 | #define ZMQ_USE_FD 89 109 | //+------------------------------------------------------------------+ 110 | //| A dedicated class to get/set socket options | 111 | //+------------------------------------------------------------------+ 112 | class SocketOptions 113 | { 114 | protected: 115 | intptr_t m_ref; 116 | 117 | #define SOCKOPT_WRAP_ARRAY(TYPE) \ 118 | bool setOption(int option,const TYPE &value[],size_t len) {return 0==zmq_setsockopt(m_ref,option,value,len);}\ 119 | bool getOption(int option,TYPE &value[],size_t &len) {return 0==zmq_getsockopt(m_ref,option,value,len);} 120 | 121 | #define SOCKOPT_WRAP(TYPE) \ 122 | bool setOption(int option,TYPE value) {return 0==zmq_setsockopt(m_ref,option,value,sizeof(TYPE));}\ 123 | bool getOption(int option,TYPE &value) {size_t s=sizeof(TYPE); return 0==zmq_getsockopt(m_ref,option,value,s);} 124 | 125 | SOCKOPT_WRAP_ARRAY(uchar) 126 | SOCKOPT_WRAP(int) 127 | SOCKOPT_WRAP(uint) 128 | SOCKOPT_WRAP(long) 129 | SOCKOPT_WRAP(ulong) 130 | 131 | bool setStringOption(int option,string value,bool ending=true); 132 | bool getStringOption(int option,string &value,size_t length=1024); 133 | SocketOptions(intptr_t ref):m_ref(ref){} 134 | public: 135 | //--- option templates 136 | //--- various integer options 137 | #define SOCKOPT_GET(TYPE, NAME, MACRO) \ 138 | bool get##NAME(TYPE &value) {return getOption(MACRO,value);} 139 | #define SOCKOPT_SET(TYPE, NAME, MACRO) \ 140 | bool set##NAME(TYPE value) {return setOption(MACRO,value);} 141 | #define SOCKOPT(TYPE,NAME,MACRO) \ 142 | SOCKOPT_GET(TYPE,NAME,MACRO) \ 143 | SOCKOPT_SET(TYPE,NAME,MACRO) 144 | 145 | //--- boolean options 146 | #define SOCKOPT_GET_BOOL(NAME, MACRO) \ 147 | bool is##NAME(bool &value) {int v; bool res=getOption(MACRO,v); value=(v==1);return res;} 148 | #define SOCKOPT_SET_BOOL(NAME, MACRO) \ 149 | bool set##NAME(bool value) {return setOption(MACRO,value?1:0);} 150 | #define SOCKOPT_BOOL(NAME,MACRO) \ 151 | SOCKOPT_GET_BOOL(NAME,MACRO) \ 152 | SOCKOPT_SET_BOOL(NAME,MACRO) 153 | 154 | //--- null-terminated string options 155 | #define SOCKOPT_GET_NTSTR(NAME,MACRO) \ 156 | bool get##NAME(string &value) {return getStringOption(MACRO,value);} 157 | #define SOCKOPT_SET_NTSTR(NAME,MACRO) \ 158 | bool set##NAME(string value) {return setStringOption(MACRO,value);} 159 | #define SOCKOPT_NTSTR(NAME,MACRO) \ 160 | SOCKOPT_GET_NTSTR(NAME,MACRO) \ 161 | SOCKOPT_SET_NTSTR(NAME,MACRO) 162 | 163 | //--- bytes array or string converted options 164 | #define SOCKOPT_SET_BYTES(OptionName,Macro) \ 165 | bool set##OptionName(const uchar &value[]) {return setOption(Macro,value,(size_t)ArraySize(value));} \ 166 | bool set##OptionName(string value) {return setStringOption(Macro,value,false);} 167 | #define SOCKOPT_GET_BYTES(OptionName,Macro,InitSize) \ 168 | bool get##OptionName(uchar &value[]) {size_t len=(size_t)InitSize; ArrayResize(value,(int)len); bool res=getOption(Macro,value,len); if(res){ArrayResize(value,(int)len);}return res;} \ 169 | bool get##OptionName(string &value) {return getStringOption(Macro,value,InitSize);} 170 | #define SOCKOPT_BYTES(OptionName,Macro,InitSize) \ 171 | SOCKOPT_SET_BYTES(OptionName,Macro) \ 172 | SOCKOPT_GET_BYTES(OptionName,Macro,InitSize) 173 | 174 | //--- for curve key 175 | #define SOCKOPT_CURVE_KEY(KeyType,Macro) \ 176 | bool getCurve##KeyType##Key(uchar &key[32]) {size_t len=32; return getOption(Macro,key,len);} \ 177 | bool getCurve##KeyType##Key(string &key) {return getStringOption(Macro,key,41);} \ 178 | bool setCurve##KeyType##Key(const uchar &key[32]) {return setOption(Macro,key,32);} \ 179 | bool setCurve##KeyType##Key(string key) {return setStringOption(Macro,key);} 180 | 181 | SOCKOPT_GET(int,Type,ZMQ_TYPE) 182 | SOCKOPT(ulong,Affinity,ZMQ_AFFINITY) //64bit bitmask 183 | SOCKOPT(int,BackLog,ZMQ_BACKLOG) // number of connections 184 | SOCKOPT(int,Timeout,ZMQ_CONNECT_TIMEOUT) // milliseconds 185 | SOCKOPT_GET_BOOL(ThreadSafe,ZMQ_THREAD_SAFE) 186 | 187 | SOCKOPT_SET_BOOL(Conflate,ZMQ_CONFLATE) // only for ZMQ_PULL, ZMQ_PUSH, ZMQ_SUB, ZMQ_PUB, ZMQ_DEALER types 188 | 189 | SOCKOPT_GET(int,Events,ZMQ_EVENTS); // bitmask of ZMQ_POLLIN, ZMQ_POLLOUT 190 | 191 | SOCKOPT_GET(uintptr_t,FileDescriptor,ZMQ_FD) 192 | 193 | SOCKOPT_GET(int,Mechanism,ZMQ_MECHANISM) // current security mechanism 194 | 195 | //--- plain 196 | SOCKOPT_NTSTR(PlainUsername,ZMQ_PLAIN_USERNAME) 197 | SOCKOPT_NTSTR(PlainPassword,ZMQ_PLAIN_PASSWORD) 198 | SOCKOPT_BOOL(PlainServer,ZMQ_PLAIN_SERVER) 199 | 200 | //--- gssapi: this is not supported in this binding. Following methods will FAIL if you invoke them 201 | SOCKOPT_BOOL(GssApiPlainText,ZMQ_GSSAPI_PLAINTEXT) 202 | SOCKOPT_BOOL(GssApiServer,ZMQ_GSSAPI_SERVER) 203 | SOCKOPT_NTSTR(GssApiPrincipal,ZMQ_GSSAPI_PRINCIPAL) 204 | SOCKOPT_NTSTR(GssApiServicePrincipal,ZMQ_GSSAPI_SERVICE_PRINCIPAL) 205 | 206 | //--- curve 207 | //SOCKOPT_CURVE_KEY(Public,ZMQ_CURVE_PUBLICKEY) 208 | //SOCKOPT_CURVE_KEY(Secret,ZMQ_CURVE_SECRETKEY) 209 | //SOCKOPT_CURVE_KEY(Server,ZMQ_CURVE_SERVERKEY) 210 | 211 | SOCKOPT_SET_BOOL(CurveServer,ZMQ_CURVE_SERVER) 212 | 213 | SOCKOPT_GET_NTSTR(LastEndpoint,ZMQ_LAST_ENDPOINT) 214 | 215 | SOCKOPT(int,HandshakeInterval,ZMQ_HANDSHAKE_IVL) // milliseconds 216 | SOCKOPT_SET(int,HeartbeatInterval,ZMQ_HEARTBEAT_IVL) // milliseconds 217 | SOCKOPT_SET(int,HeartbeatTimeout,ZMQ_HEARTBEAT_TIMEOUT) // milliseconds 218 | SOCKOPT_SET(int,HeartbeatTTL,ZMQ_HEARTBEAT_TTL) // milliseconds 219 | 220 | SOCKOPT_BOOL(Immediate,ZMQ_IMMEDIATE) 221 | SOCKOPT_BOOL(Ipv6,ZMQ_IPV6) //--- ZMQ_IPV4ONLY is deprecated, use this instead 222 | SOCKOPT(int,Linger,ZMQ_LINGER) // milliseconds 223 | SOCKOPT(long,MaxMessageSize,ZMQ_MAXMSGSIZE) 224 | 225 | //--- multicast 226 | SOCKOPT(int,MulticastHops,ZMQ_MULTICAST_HOPS) // hops 227 | SOCKOPT(int,MulticastMaxTPDU,ZMQ_MULTICAST_MAXTPDU) // bytes 228 | SOCKOPT(int,MulticastRate,ZMQ_RATE) // kilobits per second 229 | SOCKOPT(int,RecoveryInterval,ZMQ_RECOVERY_IVL) // multicast recovery interval 230 | 231 | //--- there is a problem here: FileDescriptor should be SOCKET type on Windows, 232 | //--- while in the zmq doc it is a int. Possible error in the doc 233 | SOCKOPT(uintptr_t,UseFileDescriptor,ZMQ_USE_FD) 234 | 235 | SOCKOPT_SET_BOOL(ProbeRouter,ZMQ_PROBE_ROUTER) // only for ZMQ_ROUTER, ZMQ_DEALER, ZMQ_REQ 236 | 237 | SOCKOPT(int,ReceiveBuffer,ZMQ_RCVBUF) // bytes 238 | SOCKOPT(int,ReceiveHighWaterMark,ZMQ_RCVHWM) // messages 239 | SOCKOPT(int,ReceiveTimeout,ZMQ_RCVTIMEO) // milliseconds 240 | SOCKOPT(int,SendBuffer,ZMQ_SNDBUF) // bytes 241 | SOCKOPT(int,SendHighWaterMark,ZMQ_SNDHWM) // messages 242 | SOCKOPT(int,SendTimout,ZMQ_SNDTIMEO) 243 | 244 | SOCKOPT_GET_BOOL(ReceiveMore,ZMQ_RCVMORE) 245 | 246 | SOCKOPT(int,ReconnectInterval,ZMQ_RECONNECT_IVL) // milliseconds 247 | SOCKOPT(int,ReconnectIntervalMax,ZMQ_RECONNECT_IVL_MAX) // milliseconds 248 | 249 | //--- only for ZMQ_REQ 250 | SOCKOPT_SET_BOOL(RequestCorrelated,ZMQ_REQ_CORRELATE) 251 | SOCKOPT_SET_BOOL(RequestRelaxed,ZMQ_REQ_RELAXED) 252 | 253 | //--- only for ZMQ_SUB 254 | SOCKOPT_SET_BYTES(Subscribe,ZMQ_SUBSCRIBE) 255 | SOCKOPT_SET_BYTES(Unsubscribe,ZMQ_UNSUBSCRIBE) 256 | 257 | //--- convenience methods 258 | bool subscribe(string channel) {return setSubscribe(channel);} 259 | bool unsubscribe(string channel) {return setUnsubscribe(channel);} 260 | 261 | //--- only for ZMQ_XSUB 262 | SOCKOPT_BOOL(XpubVerbose,ZMQ_XPUB_VERBOSE) 263 | SOCKOPT_BOOL(XpubVerboser,ZMQ_XPUB_VERBOSER) 264 | SOCKOPT_BOOL(XpubManual,ZMQ_XPUB_MANUAL) 265 | SOCKOPT_BOOL(XpubNoDrop,ZMQ_XPUB_NODROP) // also for ZMQ_PUB 266 | SOCKOPT_SET_BYTES(XpubWelcomeMessage,ZMQ_XPUB_WELCOME_MSG) 267 | 268 | SOCKOPT_BOOL(InvertMatching,ZMQ_INVERT_MATCHING) //--- only for ZMQ_PUB, ZMQ_XPUB, ZMQ_SUB 269 | 270 | //--- only for ZMQ_ROUTER 271 | SOCKOPT_SET_BOOL(RouterHandover,ZMQ_ROUTER_HANDOVER) 272 | SOCKOPT_SET_BOOL(RouterMandatory,ZMQ_ROUTER_MANDATORY) 273 | SOCKOPT_SET_BOOL(RouterRaw,ZMQ_ROUTER_RAW) 274 | 275 | //--- only for ZMQ_STREAM 276 | SOCKOPT_SET_BOOL(StreamNotify,ZMQ_STREAM_NOTIFY) 277 | 278 | //--- only for ZMQ_ROUTER, ZMQ_STREAM 279 | SOCKOPT_SET_BYTES(ConnectRid,ZMQ_CONNECT_RID) 280 | 281 | //--- only for ZMQ_REP, ZMQ_REQ, ZMQ_ROUTER, ZMQ_DEALER 282 | SOCKOPT_BYTES(Identity,ZMQ_IDENTITY,255) 283 | 284 | //--- tcp 285 | SOCKOPT(int,TcpKeepAlive,ZMQ_TCP_KEEPALIVE) 286 | SOCKOPT(int,TcpKeepAliveCount,ZMQ_TCP_KEEPALIVE_CNT) 287 | SOCKOPT(int,TcpKeepAliveIdle,ZMQ_TCP_KEEPALIVE_IDLE) 288 | SOCKOPT(int,TcpKeepAliveInterval,ZMQ_TCP_KEEPALIVE_INTVL) 289 | SOCKOPT(int,TcpMaxRetransmitTimeout,ZMQ_TCP_MAXRT) 290 | 291 | SOCKOPT(int,TypeOfService,ZMQ_TOS) // IP_TOS 292 | 293 | //--- ZMQ_TCP_ACCEPT_FILTER 294 | //--- ZMQ_IPC_FILTER_GID 295 | //--- ZMQ_IPC_FILTER_PID 296 | //--- ZMQ_IPC_FILTER_UID 297 | //--- are deprecated in favor of ZAP API and ip address whitelisting/blacklisting 298 | SOCKOPT_NTSTR(ZapDomain,ZMQ_ZAP_DOMAIN) 299 | 300 | //--- only for vmci transport 301 | SOCKOPT(ulong,VmciBufferSize,ZMQ_VMCI_BUFFER_SIZE) // bytes 302 | SOCKOPT(ulong,VmciBufferMinSize,ZMQ_VMCI_BUFFER_MIN_SIZE) // bytes 303 | SOCKOPT(ulong,VmciBufferMaxSize,ZMQ_VMCI_BUFFER_MAX_SIZE) // bytes 304 | SOCKOPT(int,VmciConnectTimeout,ZMQ_VMCI_CONNECT_TIMEOUT) // milliseconds 305 | }; 306 | //+------------------------------------------------------------------+ 307 | //| The option value is a string with predefined byte length | 308 | //| | 309 | //| If it is a NULL-terminated string without predefined length, | 310 | //| The situation is tricky: we do not know the length of the option | 311 | //| value beforehand, but the function does not return the correct | 312 | //| one, either. So the only option is to guess. | 313 | //| | 314 | //| Here we adopt the solution of the Java binding. We just guess | 315 | //| that the length of a NULL-terminated string option is less than | 316 | //| 1024. So hopefully, it is the case. | 317 | //+------------------------------------------------------------------+ 318 | bool SocketOptions::getStringOption(int option,string &value,size_t length) 319 | { 320 | char buf[]; 321 | ArrayResize(buf,(int)length); 322 | bool res=getOption(option,buf,length); 323 | if(res) 324 | { 325 | value=StringFromUtf8(buf); 326 | } 327 | ArrayFree(buf); 328 | return res; 329 | } 330 | //+------------------------------------------------------------------+ 331 | //| The ending means that the converted buffer contains the ending | 332 | //| null. | 333 | //+------------------------------------------------------------------+ 334 | bool SocketOptions::setStringOption(int option,const string value,bool ending) 335 | { 336 | char buf[]; 337 | StringToUtf8(value,buf,ending); 338 | int len = ArraySize(buf); 339 | bool res=setOption(option,buf,len); 340 | ArrayFree(buf); 341 | return res; 342 | } 343 | //+------------------------------------------------------------------+ 344 | -------------------------------------------------------------------------------- /MQL4/Include/Zmq/Z85.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Z85.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | 11 | #include "Common.mqh" 12 | 13 | #import "libzmq.dll" 14 | // Encode data with Z85 encoding. Returns 0(NULL) if failed 15 | intptr_t zmq_z85_encode(char &str[],const uchar &data[],size_t size); 16 | 17 | // Decode data with Z85 encoding. Returns 0(NULL) if failed 18 | intptr_t zmq_z85_decode(uchar &dest[],const char &str[]); 19 | 20 | // Generate z85-encoded public and private keypair with tweetnacl/libsodium 21 | int zmq_curve_keypair(char &z85_public_key[],char &z85_secret_key[]); 22 | 23 | // Derive the z85-encoded public key from the z85-encoded secret key 24 | int zmq_curve_public(char &z85_public_key[],const char &z85_secret_key[]); 25 | #import 26 | //+------------------------------------------------------------------+ 27 | //| Z85 encoding/decoding | 28 | //+------------------------------------------------------------------+ 29 | class Z85 30 | { 31 | public: 32 | static bool encode(string &secret,const uchar &data[]); 33 | static bool decode(const string secret,uchar &data[]); 34 | 35 | static string encode(string data); 36 | static string decode(string secret); 37 | 38 | static bool generateKeyPair(uchar &publicKey[],uchar &secretKey[]); 39 | static bool derivePublic(uchar &publicKey[],const uchar &secretKey[]); 40 | 41 | static bool generateKeyPair(string &publicKey,string &secretKey); 42 | static string derivePublic(const string secretKey); 43 | }; 44 | //+------------------------------------------------------------------+ 45 | //| data must have size multiple of 4 | 46 | //+------------------------------------------------------------------+ 47 | bool Z85::encode(string &secret,const uchar &data[]) 48 | { 49 | int size=ArraySize(data); 50 | if(size%4 != 0) return false; 51 | 52 | char str[]; 53 | ArrayResize(str,(int)(1.25*size+1)); 54 | 55 | intptr_t res=zmq_z85_encode(str,data,size); 56 | if(res == 0) return false; 57 | secret = StringFromUtf8(str); 58 | return true; 59 | } 60 | //+------------------------------------------------------------------+ 61 | //| secret must be multiples of 5 | 62 | //+------------------------------------------------------------------+ 63 | bool Z85::decode(const string secret,uchar &data[]) 64 | { 65 | int len=StringLen(secret); 66 | if(len%5 != 0) return false; 67 | 68 | char str[]; 69 | StringToUtf8(secret,str); 70 | ArrayResize(data,(int)(0.8*len)); 71 | return 0 != zmq_z85_decode(data,str); 72 | } 73 | //+------------------------------------------------------------------+ 74 | //| data length should be multiples of 4 and only ascii is supported | 75 | //+------------------------------------------------------------------+ 76 | string Z85::encode(string data) 77 | { 78 | char str[]; 79 | StringToUtf8(data,str,false); 80 | string res; 81 | if(encode(res,str)) 82 | return res; 83 | else 84 | return ""; 85 | } 86 | //+------------------------------------------------------------------+ 87 | //| secret must be multiples of 5 | 88 | //+------------------------------------------------------------------+ 89 | string Z85::decode(string secret) 90 | { 91 | uchar data[]; 92 | decode(secret,data); 93 | return StringFromUtf8(data); 94 | } 95 | //+------------------------------------------------------------------+ 96 | //| | 97 | //+------------------------------------------------------------------+ 98 | bool Z85::generateKeyPair(uchar &publicKey[],uchar &secretKey[]) 99 | { 100 | ArrayResize(publicKey,41); 101 | ArrayResize(secretKey,41); 102 | return 0==zmq_curve_keypair(publicKey, secretKey); 103 | } 104 | //+------------------------------------------------------------------+ 105 | //| | 106 | //+------------------------------------------------------------------+ 107 | bool Z85::derivePublic(uchar &publicKey[],const uchar &secretKey[]) 108 | { 109 | ArrayResize(publicKey,41); 110 | return 0==zmq_curve_public(publicKey, secretKey); 111 | } 112 | //+------------------------------------------------------------------+ 113 | //| | 114 | //+------------------------------------------------------------------+ 115 | bool Z85::generateKeyPair(string &publicKey,string &secretKey) 116 | { 117 | uchar sec[],pub[]; 118 | bool res=generateKeyPair(pub,sec); 119 | if(res) 120 | { 121 | secretKey=StringFromUtf8(sec); 122 | publicKey=StringFromUtf8(pub); 123 | } 124 | ArrayFree(sec); 125 | ArrayFree(pub); 126 | return res; 127 | } 128 | //+------------------------------------------------------------------+ 129 | //| | 130 | //+------------------------------------------------------------------+ 131 | string Z85::derivePublic(const string secrect) 132 | { 133 | uchar sec[],pub[]; 134 | StringToUtf8(secrect,sec); 135 | derivePublic(pub,sec); 136 | string pubstr=StringFromUtf8(pub); 137 | ArrayFree(sec); 138 | ArrayFree(pub); 139 | return pubstr; 140 | } 141 | //+------------------------------------------------------------------+ 142 | -------------------------------------------------------------------------------- /MQL4/Include/Zmq/Zmq.mqh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL4/Include/Zmq/Zmq.mqh -------------------------------------------------------------------------------- /MQL4/Include/Zmq/ZmqMsg.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| ZmqMsg.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | #include "Common.mqh" 11 | //+------------------------------------------------------------------+ 12 | //| 0MQ Message struct | 13 | //+------------------------------------------------------------------+ 14 | // align sizeof(intptr_t) 15 | // = 8 on 64bit 16 | // = 4 on 32bit 17 | // hopefully MetaQuotes do malloc structs 18 | // aligned on pointer address boundaries 19 | struct zmq_msg_t 20 | { 21 | uchar _[64]; 22 | }; 23 | 24 | #import "libzmq.dll" 25 | int zmq_msg_init(zmq_msg_t &msg); 26 | int zmq_msg_init_size(zmq_msg_t &msg,size_t size); 27 | // As mt4 can not provide a zmq_free_fn, and can not let 28 | // zmq library own the array data, copying is always needed. 29 | // Therefore this function will not be used by this binding. 30 | // int zmq_msg_init_data(zmq_msg_t &msg,uchar &data[], 31 | // int size,int ffn,int hint); 32 | int zmq_msg_close(zmq_msg_t &msg); 33 | int zmq_msg_move(zmq_msg_t &dest,zmq_msg_t &src); 34 | int zmq_msg_copy(zmq_msg_t &dest,zmq_msg_t &src); 35 | // char * 36 | intptr_t zmq_msg_data(zmq_msg_t &msg); 37 | int zmq_msg_size(zmq_msg_t &msg); 38 | int zmq_msg_more(zmq_msg_t &msg); 39 | int zmq_msg_get(zmq_msg_t &msg,int property); 40 | int zmq_msg_set(zmq_msg_t &msg,int property,int optval); 41 | // const char * 42 | intptr_t zmq_msg_gets(zmq_msg_t &msg,const char &property[]); 43 | #import 44 | //+------------------------------------------------------------------+ 45 | //| Wraps a zmq_msg_t | 46 | //+------------------------------------------------------------------+ 47 | struct ZmqMsg: public zmq_msg_t 48 | { 49 | protected: 50 | int get(int property) {return zmq_msg_get(this,property);} 51 | bool set(int property,int value) {return 0==zmq_msg_set(this,property,value);} 52 | intptr_t data() {return zmq_msg_data(this);} 53 | public: 54 | ZmqMsg() {zmq_msg_init(this);} 55 | ZmqMsg(int size) {if(0!=zmq_msg_init_size(this,size)){Debug("Failed to init size msg: insufficient space");}} 56 | ZmqMsg(string data,bool nullterminated=false); 57 | ~ZmqMsg() {if(0!=zmq_msg_close(this)){Debug("Failed to close msg");}} 58 | 59 | size_t size() {return zmq_msg_size(this);} 60 | 61 | void getData(uchar &data[]); 62 | string getData(); 63 | void setData(const uchar &data[]); 64 | 65 | bool more() {return 1==zmq_msg_more(this);} 66 | 67 | bool copy(ZmqMsg &msg) {return 0 == zmq_msg_copy(this, msg);} 68 | bool move(ZmqMsg &msg) {return 0 == zmq_msg_move(this, msg);} 69 | 70 | string meta(const string property); 71 | }; 72 | //+------------------------------------------------------------------+ 73 | //| Initialize a utf-8 string message | 74 | //+------------------------------------------------------------------+ 75 | ZmqMsg::ZmqMsg(string data,bool nullterminated) 76 | { 77 | uchar array[]; 78 | StringToUtf8(data,array,nullterminated); 79 | int size=ArraySize(array); 80 | zmq_msg_init_size(this,size); 81 | setData(array); 82 | } 83 | //+------------------------------------------------------------------+ 84 | //| Get message data as bytes array | 85 | //+------------------------------------------------------------------+ 86 | void ZmqMsg::getData(uchar &data[]) 87 | { 88 | size_t size=size(); 89 | intptr_t src=data(); 90 | ArrayResize(data,(int)size); 91 | ArrayFromPointer(data,src); 92 | } 93 | //+------------------------------------------------------------------+ 94 | //| Get message data as utf-8 string | 95 | //+------------------------------------------------------------------+ 96 | string ZmqMsg::getData() 97 | { 98 | size_t size=size(); 99 | intptr_t psz=data(); 100 | return StringFromUtf8Pointer(psz,(int)size); 101 | } 102 | //+------------------------------------------------------------------+ 103 | //| copy data to message internal storage | 104 | //+------------------------------------------------------------------+ 105 | void ZmqMsg::setData(const uchar &data[]) 106 | { 107 | intptr_t dest=data(); 108 | ArrayToPointer(data,dest); 109 | } 110 | //+------------------------------------------------------------------+ 111 | //| Wraps zmq_msg_gets: get metadata associated with the msg | 112 | //+------------------------------------------------------------------+ 113 | string ZmqMsg::meta(const string property) 114 | { 115 | uchar buf[]; 116 | StringToUtf8(property,buf); 117 | intptr_t ref=zmq_msg_gets(this,buf); 118 | ArrayFree(buf); 119 | return StringFromUtf8Pointer(ref); 120 | } 121 | //+------------------------------------------------------------------+ 122 | -------------------------------------------------------------------------------- /MQL4/Include/hash.mqh: -------------------------------------------------------------------------------- 1 | // $Id: hash.mqh 125 2014-03-03 08:38:32Z ydrol $ 2 | #ifndef YDROL_HASH_MQH 3 | #define YDROL_HASH_MQH 4 | 5 | //#property strict 6 | 7 | /* 8 | This is losely ported from a C version I have which was in turn modified from hashtable.c by Christopher Clark. 9 | Copyright (C) 2014, Andrew Lord (NICKNAME=lordy) 10 | Copyright (C) 2002, 2004 Christopher Clark 11 | 12 | 2014/02/21 - Readded PrimeNumber sizes and auto rehashing when load factor hit. 13 | */ 14 | 15 | 16 | 17 | /// Any value stored in a Hash must be a subclass of HashValue 18 | class HashValue { 19 | }; 20 | 21 | /// Linked list of values - there will be one list for each hash value 22 | class HashEntry { 23 | public: 24 | string _key; 25 | HashValue * _val; 26 | HashEntry *_next; 27 | 28 | HashEntry() { 29 | _key=NULL; 30 | _val=NULL; 31 | _next=NULL; 32 | } 33 | 34 | HashEntry(string key,HashValue* val) { 35 | _key=key; 36 | _val=val; 37 | _next=NULL; 38 | } 39 | 40 | ~HashEntry() { 41 | } 42 | }; 43 | 44 | /// Convenience class for storing strings as hash values. 45 | class HashString : public HashValue { 46 | private: 47 | string val; 48 | public: 49 | HashString(string v) { val=v;} 50 | string getVal() { return val; } 51 | }; 52 | 53 | /// Convenience class for storing doubles as hash values. 54 | class HashDouble : public HashValue { 55 | private: 56 | double val; 57 | public: 58 | HashDouble(double v) { val=v;} 59 | double getVal() { return val; } 60 | }; 61 | 62 | /// Convenience class for storing ints as hash values. 63 | class HashInt : public HashValue { 64 | private: 65 | int val; 66 | public: 67 | HashInt(int v) { val=v;} 68 | int getVal() { return val; } 69 | }; 70 | 71 | /// Convenience class for storing longs as hash values. 72 | class HashLong : public HashValue { 73 | private: 74 | long val; 75 | public: 76 | HashLong(datetime v) { val=v;} 77 | long getVal() { return val; } 78 | 79 | }; 80 | 81 | /// Convenience class for storing datetimes as hash values. 82 | class HashDatetime : public HashValue { 83 | private: 84 | datetime val; 85 | public: 86 | HashDatetime(datetime v) { val=v;} 87 | datetime getVal() { return val; } 88 | }; 89 | 90 | /// 91 | /// Hash class allows objects to be stored in a table index by strings. 92 | /// the stored Objects must be a sub class of the HashValue class. 93 | /// 94 | /// There are some convenience classes to hold atomic types as values HashString,HashDouble,HashInt 95 | /// 96 | ///EXAMPLE: 97 | /// 98 | ///
 99 | /// class myClass: public HashValue {
100 | ///   public: int v;
101 | ///   myClass(int a) { v = a;}
102 | /// };
103 | ///
104 | /// // Create the objects as needed
105 | ///
106 | ///      myClass *a = new myClass(1);
107 | ///      myClass *b = new myClass(2);
108 | ///      myClass *c = new myClass(3);
109 | ///
110 | /// // Then to insert into hash etc.
111 | ///
112 | ///      Hash* h = new Hash(193,true); 
113 | ///      // 'true' means when the hash will adopt the values and delete them when they are removed from the hash or when the hash is deleted.
114 | ///
115 | ///      h.hPut("a",a);
116 | ///      h.hPut("b",b);
117 | ///      h.hPut("c",c);
118 | ///
119 | ///      myClass *d = h.hGet("b");
120 | ///
121 | ///      etc.
122 | ///
123 | /// // Iterate over hash
124 | ///    HashLoop *l
125 | ///    for (l = new HashLoop(h) ; l.hasNext() ; l.next()  ) {
126 | ///        string key = l.key();
127 | ///        MyClass *c = l.val();
128 | ///    }
129 | ///    delete l;
130 | ///
131 | ///    // Delete from hash - This will also delete 'a' because we set the 'adopt' flag on the hash.
132 | ///    h.hDel("a");
133 | ///
134 | ///    //Delete the hash - this will also delete 'b' and 'c' because of the adopt flag.
135 | ///    delete h;
136 | /// 
137 | class Hash : public HashValue { 138 | 139 | private: 140 | /// Number of slots in the hashtable. 141 | /// this should be approx number of elements to store. Depending on hash algorithm 142 | /// it may optimally be a prime or a power of two etc. but probably not important 143 | /// for MQL4 performance. A future optimisation might be to move the hashcode function to a DLL?? 144 | uint _hashSlots; 145 | 146 | /// Number of elements at which hash will get resized. 147 | int _resizeThreshold; 148 | 149 | /// number of things in the hash 150 | int _hashEntryCount; 151 | 152 | /// an array of linked lists (HashEntry). one for each hash value. 153 | /// To store an object against a string(key) - get the string hashcode, then insert pair (key,val) into the linked list for that hashcode. 154 | /// To fetch an object against a string(key) - get the string hashcode, get linked-list at that hashcode index, then search for the key and return the val. 155 | HashEntry* _buckets[]; 156 | 157 | /// If true the hash will free(delete) values as they are removed, or at cleanup. 158 | bool _adoptValues; 159 | 160 | int _errCode; 161 | string _errText; 162 | 163 | void init(uint size,bool adoptValues) 164 | { 165 | _hashSlots = 0; 166 | _hashEntryCount = 0; 167 | clearError(); 168 | setAdoptValues(adoptValues); 169 | 170 | rehash(size); 171 | } 172 | 173 | // Hash table distribution is better when size is prime, eg if hash function procduces numbers 174 | // that are multiples of x, then there may be grouping occuring around gcd(x,slots) gcd(2x,slots) etc 175 | // using a prime size helps spread the distribution. 176 | uint size2prime(uint size) { 177 | int pmax=ArraySize(_primes); 178 | for(int p=0 ; p= size) { 180 | return _primes[p]; 181 | } 182 | } 183 | return size; 184 | } 185 | 186 | /// Primes that approx double in size, used for hash table sizes to avoid gcd causing bunching 187 | static uint _primes[]; 188 | 189 | /// After reviewing quite a few hash functions I settled on the one below. 190 | /// http://www.cse.yorku.ca/~oz/hash.html 191 | /// this is the bottleneck function. Shame mql hash no default hash method for objects. 192 | uint hash(string s) 193 | { 194 | 195 | uchar c[]; 196 | uint h = 0; 197 | 198 | if (s != NULL) { 199 | h = 5381; 200 | int n = StringToCharArray(s,c); 201 | for(int i = 0 ; i < n ; i++ ) { 202 | h = ((h << 5 ) + h ) + c[i]; 203 | } 204 | } 205 | return h % _hashSlots; 206 | } 207 | void clearError() { 208 | setError(0,""); 209 | } 210 | void setError(int e,string m) { 211 | _errCode = e; 212 | _errText = m; 213 | //error((string)e,m); 214 | } 215 | 216 | public: 217 | 218 | /// Constructor: Create a Hash Object 219 | Hash() { 220 | init(17,true); 221 | } 222 | 223 | 224 | /// Constructor: Create a Hash Object 225 | /// @param adoptValues : If true the hash destructor will delete all dynamically allocated hash values. 226 | Hash(bool adoptValues) { 227 | init(17,adoptValues); 228 | } 229 | 230 | /// Constructor: Create a Hash Object 231 | /// @param size : Approximate size (actual size will be a larger prime number close to a power of 2) 232 | /// @param adoptValues : If true the hash destructor will delete all dynamically allocated hash values. 233 | Hash(int size,bool adoptValues) { 234 | init(size,adoptValues); 235 | } 236 | 237 | ~Hash() { 238 | 239 | // Free entries. 240 | for(uint i = 0 ; i< _hashSlots ; i++) { 241 | HashEntry *nextEntry = NULL; 242 | for(HashEntry *entry = _buckets[i] ; entry!= NULL ; entry = nextEntry ) 243 | { 244 | nextEntry = entry._next; 245 | 246 | if (_adoptValues && entry._val != NULL && CheckPointer(entry._val) == POINTER_DYNAMIC ) { 247 | delete entry._val; 248 | } 249 | delete entry; 250 | } 251 | _buckets[i] = NULL; 252 | } 253 | } 254 | 255 | /// Return any error that has occured. This should be used when 256 | /// retriving values in a Hash that may contain NULLs. hGet() 257 | /// methods can return NULL if not found, in which case getErrorCode 258 | /// will be set. 259 | int getErrCode() { 260 | return _errCode; 261 | } 262 | /// Return text of the error message. 263 | string getErrText() { 264 | return _errText; 265 | } 266 | 267 | /// If true the hash destructor will delete all dynamically allocated hash values. 268 | void setAdoptValues(bool v) { 269 | _adoptValues = v; 270 | } 271 | 272 | /// True if the hash destructor will delete all dynamically allocated hash values. 273 | bool getAdoptValues() { 274 | return _adoptValues; 275 | } 276 | 277 | private: 278 | uint _foundIndex; // After find() is called is set to hashindex for name whether found or not. 279 | HashEntry* _foundEntry; // After find() is called is set to the HashEntry that contains the key. 280 | HashEntry* _foundPrev; // After find() is called is set to the HashEntry before the entry 281 | // (could use double linked list but requires more memory). 282 | 283 | /// Look for the required entry for key 'name' true if found. 284 | bool find(string keyName) { 285 | 286 | //Alert("finding"); 287 | bool found = false; 288 | 289 | // Get the index using the hashcode of the string 290 | _foundIndex = hash(keyName); 291 | 292 | 293 | if (_foundIndex>_hashSlots ) { 294 | 295 | setError(1,"hGet: bad hashIndex="+(string)_foundIndex+" size "+(string)_hashSlots); 296 | 297 | } else { 298 | 299 | // Search the linked list determined by the index. 300 | 301 | for(HashEntry *e = _buckets[_foundIndex] ; e != NULL ; e = e._next ) { 302 | if (e._key == keyName) { 303 | _foundEntry = e; 304 | found=true; 305 | break; 306 | } 307 | // Track the item before the target item in case deleting from single linked list. 308 | _foundPrev = e; 309 | } 310 | } 311 | 312 | return found; 313 | } 314 | 315 | public: 316 | 317 | /// This is used by the HashLoop class to get start of LinkedList at bucket[i] 318 | HashEntry*getEntry(int i) { 319 | return _buckets[i]; 320 | } 321 | 322 | /// Return the number of slots/buckets (not number of elements) 323 | uint getSlots() { 324 | return _hashSlots; 325 | } 326 | /// Return the number of elements in the Hash 327 | int getCount() { 328 | return _hashEntryCount; 329 | } 330 | 331 | /// Change the hash size and re-allocate values to new buckets. 332 | bool rehash(uint newSize) { 333 | bool ret = false; 334 | HashEntry* oldTable[]; 335 | 336 | uint oldSize = _hashSlots; 337 | newSize = size2prime(newSize); 338 | //info("rehashing from "+(string)_hashSlots+" to "+(string)newSize+" "+(string)GetTickCount()); 339 | 340 | if (newSize <= getSlots()) { 341 | setError(2,"rehash "+(string)newSize+" <= "+(string)_hashSlots); 342 | } else if (ArrayResize(_buckets,newSize) != newSize) { 343 | setError(3,"unable to resize "); 344 | } else if (ArrayResize(oldTable,oldSize) != oldSize) { 345 | setError(4,"unable to resize old copy "); 346 | } else { 347 | //Copy old table. 348 | uint i; 349 | for(i = 0 ; i < oldSize ; i++ ) oldTable[i] = _buckets[i]; 350 | // Init new entries - not sure if MQL does this anyway 351 | for(i = 0 ; ikeyName key. This will overwrite any existing 459 | /// value. It adoptValues is set, it will also free the value if applicable. 460 | /// @param keyName : key name 461 | /// @param obj : Value to store 462 | /// @return the previous value of the key or NULL if there wasnt one 463 | HashValue *hPut(string keyName,HashValue *obj) { 464 | 465 | HashValue *ret = NULL; 466 | clearError(); 467 | 468 | if (find(keyName)) { 469 | // Return revious value 470 | ret = _foundEntry._val; 471 | /* 472 | // Replace entry contents 473 | if (_adoptValues && _foundEntry._val != NULL && CheckPointer(_foundEntry._val) == POINTER_DYNAMIC ) { 474 | delete _foundEntry._val; 475 | } 476 | */ 477 | _foundEntry._val = obj; 478 | 479 | } else { 480 | // Insert new entry at head of list 481 | HashEntry* e = new HashEntry(keyName,obj); 482 | HashEntry* first = _buckets[_foundIndex]; 483 | e._next = first; 484 | _buckets[_foundIndex] = e; 485 | _hashEntryCount++; 486 | 487 | //info((string)_hashEntryCount+" vs. "+(string)_resizeThreshold); 488 | // Auto Resize if number of entries hits _resizeThreshold 489 | if (_hashEntryCount > _resizeThreshold ) { 490 | rehash(_hashSlots/2*3); // this will snap to the next prime 491 | } 492 | } 493 | return ret; 494 | } 495 | /// Store a string as hash value (HashString) 496 | /// @return the previous value of the key or NULL if there wasnt one 497 | HashValue* hPutString(string keyName,string s) { 498 | HashString *v = new HashString(s); 499 | return hPut(keyName,v); 500 | } 501 | /// Store a double as hash value (HashDouble) 502 | /// @return the previous value of the key or NULL if there wasnt one 503 | HashValue* hPutDouble(string keyName,double d) { 504 | HashDouble *v = new HashDouble(d); 505 | return hPut(keyName,v); 506 | } 507 | /// Store an int as hash value (HashInt) 508 | /// @return the previous value of the key or NULL if there wasnt one 509 | HashValue* hPutInt(string keyName,int i) { 510 | HashInt *v = new HashInt(i); 511 | return hPut(keyName,v); 512 | } 513 | 514 | /// Store a datetime as hash value (HashLong) 515 | /// @return the previous value of the key or NULL if there wasnt one 516 | HashValue* hPutLong(string keyName,long i) { 517 | HashLong *v = new HashLong(i); 518 | return hPut(keyName,v); 519 | } 520 | 521 | /// Store a datetime as hash value (HashDatetime) 522 | /// @return the previous value of the key or NULL if there wasnt one 523 | HashValue* hPutDatetime(string keyName,datetime i) { 524 | HashDatetime *v = new HashDatetime(i); 525 | return hPut(keyName,v); 526 | } 527 | 528 | /// Delete an entry from the hash. 529 | bool hDel(string keyName) { 530 | 531 | bool found = false; 532 | clearError(); 533 | 534 | if (find(keyName)) { 535 | HashEntry *next = _foundEntry._next; 536 | if (_foundPrev != NULL) { 537 | //Remove entry from the middle of the list. 538 | _foundPrev._next = next; 539 | } else { 540 | // remove from head of list 541 | _buckets[_foundIndex] = next; 542 | } 543 | 544 | if (_adoptValues && _foundEntry._val != NULL&& CheckPointer(_foundEntry._val) == POINTER_DYNAMIC) { 545 | delete _foundEntry._val; 546 | } 547 | delete _foundEntry; 548 | _hashEntryCount--; 549 | found=true; 550 | 551 | } 552 | return found; 553 | } 554 | }; 555 | uint Hash::_primes[] = { 556 | 17, 53, 97, 193, 389, 557 | 769, 1543, 3079, 6151, 558 | 12289, 24593, 49157, 98317, 559 | 196613, 393241, 786433, 1572869, 560 | 3145739, 6291469, 12582917, 25165843, 561 | 50331653, 100663319, 201326611, 402653189, 562 | 805306457, 1610612741}; 563 | 564 | /// Class to iterate over a Hash using ... 565 | ///
566 | ///   HashLoop *l
567 | ///   for (l = new HashLoop(h) ; l.hasNext() ; l.next()  ) {
568 | ///       string key = l.key();
569 | ///       MyClass *c = l.val();
570 | ///   }
571 | ///   delete l;
572 | /// 
573 | class HashLoop { 574 | private: 575 | uint _index; 576 | HashEntry *_currentEntry; 577 | Hash *_hash; 578 | 579 | public: 580 | /// Create iterator for a hash - move to first item 581 | HashLoop(Hash *h) { 582 | setHash(h); 583 | } 584 | ~HashLoop() {}; 585 | 586 | /// Clear current state and move to first item (if any). 587 | void reset() { 588 | _index=0; 589 | _currentEntry = _hash.getEntry(_index); 590 | 591 | // Move to first item 592 | if (_currentEntry == NULL) { 593 | next(); 594 | } 595 | } 596 | 597 | /// Change the hash over which to iterate. 598 | void setHash(Hash *h) { 599 | _hash = h; 600 | reset(); 601 | } 602 | 603 | /// Check if more items. 604 | bool hasNext() { 605 | bool ret = ( _currentEntry != NULL); 606 | //config("hasNext=",ret); 607 | return ret; 608 | } 609 | 610 | /// Move to next item. 611 | void next() { 612 | 613 | //config("next : index = ",_index); 614 | 615 | // Advance 616 | if (_currentEntry != NULL) { 617 | _currentEntry = _currentEntry._next; 618 | } 619 | 620 | // Keep advancing if _currentEntry is null 621 | while (_currentEntry==NULL) { 622 | _index++; 623 | if (_index >= _hash.getSlots() ) return ; 624 | _currentEntry = _hash.getEntry(_index); 625 | } 626 | } 627 | 628 | /// Return the key name of the current item. 629 | string key() { 630 | if (_currentEntry != NULL) { 631 | return _currentEntry._key; 632 | } else { 633 | return NULL; 634 | } 635 | } 636 | 637 | /// Return the value. 638 | HashValue *val() { 639 | if (_currentEntry != NULL) { 640 | return _currentEntry._val; 641 | } else { 642 | return NULL; 643 | } 644 | } 645 | 646 | /// Convenience functions for retriving int from a current HashInt entry 647 | int valInt() { 648 | return ((HashInt *)val()).getVal(); 649 | } 650 | 651 | /// Convenience functions for retriving int from a current HashString entry 652 | string valString() { 653 | return ((HashString *)val()).getVal(); 654 | } 655 | 656 | /// Convenience functions for retriving int from a current HashDouble entry 657 | double valDouble() { 658 | return ((HashDouble *)val()).getVal(); 659 | } 660 | 661 | /// Convenience functions for retriving int from a current HashLong entry 662 | long valLong() { 663 | return ((HashLong *)val()).getVal(); 664 | } 665 | /// Convenience functions for retriving int from a current HashDatetime entry 666 | datetime valDatetime() { 667 | return ((HashDatetime *)val()).getVal(); 668 | } 669 | }; 670 | 671 | 672 | #endif -------------------------------------------------------------------------------- /MQL4/Libraries/libsodium.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL4/Libraries/libsodium.dll -------------------------------------------------------------------------------- /MQL4/Libraries/libzmq.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL4/Libraries/libzmq.dll -------------------------------------------------------------------------------- /MQL4/Scripts/client.mq4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL4/Scripts/client.mq4 -------------------------------------------------------------------------------- /MQL4/Scripts/server.mq4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL4/Scripts/server.mq4 -------------------------------------------------------------------------------- /MQL5/Experts/hitback/hitback.mq5: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| hitback.mq5 | 3 | //| Copyright 2017, Hitback. | 4 | //| https://www.hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback." 7 | #property link "https://www.hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | 11 | //--- Include a class of the Standard Library 12 | #include 13 | #include 14 | #include 15 | 16 | string currency = Symbol(); 17 | extern string ip_adress = "*"; 18 | extern string prefixPort = "20"; 19 | 20 | // ZMQ 21 | Context context; 22 | Socket socket(context,ZMQ_PUB); 23 | 24 | //+------------------------------------------------------------------+ 25 | //| Expert initialization function | 26 | //+------------------------------------------------------------------+ 27 | int OnInit() 28 | { 29 | 30 | MarketBookAdd(currency); 31 | 32 | // Print("using zeromq version "+getVersion()); 33 | if( socket.bind("tcp://"+serverAdress( currency )) ) 34 | { 35 | Print("Problem with ZMQ bind " + "tcp://"+serverAdress( currency )); 36 | }else{ 37 | Print("ZMQ bind " + "tcp://"+serverAdress( currency ) + " Connected"); 38 | } 39 | 40 | return(INIT_SUCCEEDED); 41 | } 42 | //+------------------------------------------------------------------+ 43 | //| Expert deinitialization function | 44 | //+------------------------------------------------------------------+ 45 | void OnDeinit(const int reason) 46 | { 47 | //--- close the DOM 48 | if(!MarketBookRelease(currency)) 49 | Print("Failed to close the DOM!"); 50 | } 51 | 52 | string serverAdress(string symbol_received) 53 | { 54 | string str = ""; 55 | 56 | if( "AUDCAD" == symbol_received ) { 57 | str=ip_adress+":"+prefixPort+"02"; 58 | return str; 59 | } 60 | 61 | if( "AUDCHF" == symbol_received ) { 62 | str=ip_adress+":"+prefixPort+"03"; 63 | return str; 64 | } 65 | 66 | if( "EURUSD" == symbol_received ) { 67 | str=ip_adress+":"+prefixPort+"04"; 68 | return str; 69 | } 70 | 71 | if( "AUDJPY" == symbol_received ) { 72 | str=ip_adress+":"+prefixPort+"05"; 73 | return str; 74 | } 75 | 76 | if( "AUDNZD" == symbol_received ) { 77 | str=ip_adress+":"+prefixPort+"06"; 78 | return str; 79 | } 80 | 81 | if( "CADCHF" == symbol_received ) { 82 | str=ip_adress+":"+prefixPort+"07"; 83 | return str; 84 | } 85 | 86 | if( "CADJPY" == symbol_received ) { 87 | str=ip_adress+":"+prefixPort+"08"; 88 | return str; 89 | } 90 | 91 | if( "CHFJPY" == symbol_received ) { 92 | str=ip_adress+":"+prefixPort+"09"; 93 | return str; 94 | } 95 | 96 | if( "EURAUD" == symbol_received ) { 97 | str=ip_adress+":"+prefixPort+"10"; 98 | return str; 99 | } 100 | 101 | if( "EURCAD" == symbol_received ) { 102 | str=ip_adress+":"+prefixPort+"11"; 103 | return str; 104 | } 105 | 106 | if( "EURCHF" == symbol_received ) { 107 | str=ip_adress+":"+prefixPort+"12"; 108 | return str; 109 | } 110 | 111 | if( "EURGBP" == symbol_received ) { 112 | str=ip_adress+":"+prefixPort+"13"; 113 | return str; 114 | } 115 | 116 | if( "GBPAUD" == symbol_received ) { 117 | str=ip_adress+":"+prefixPort+"14"; 118 | return str; 119 | } 120 | 121 | if( "GBPCAD" == symbol_received ) { 122 | str=ip_adress+":"+prefixPort+"15"; 123 | return str; 124 | } 125 | 126 | if( "GBPCHF" == symbol_received ) { 127 | str=ip_adress+":"+prefixPort+"16"; 128 | return str; 129 | } 130 | 131 | if( "GBPJPY" == symbol_received ) { 132 | str=ip_adress+":"+prefixPort+"17"; 133 | return str; 134 | } 135 | 136 | if( "GBPNZD" == symbol_received ) { 137 | str=ip_adress+":"+prefixPort+"18"; 138 | return str; 139 | } 140 | 141 | if( "NZDCHF" == symbol_received ) { 142 | str=ip_adress+":"+prefixPort+"19"; 143 | return str; 144 | } 145 | 146 | if( "NZDJPY" == symbol_received ) { 147 | str=ip_adress+":"+prefixPort+"20"; 148 | return str; 149 | } 150 | 151 | if( "NZDUSD" == symbol_received ) { 152 | str=ip_adress+":"+prefixPort+"21"; 153 | return str; 154 | } 155 | 156 | if( "EURNZD" == symbol_received) { 157 | str=ip_adress+":"+prefixPort+"22"; 158 | return str; 159 | } 160 | 161 | if( "USDCAD" == symbol_received ) { 162 | str=ip_adress+":"+prefixPort+"23"; 163 | return str; 164 | } 165 | 166 | if( "EURJPY" == symbol_received ) { 167 | str=ip_adress+":"+prefixPort+"24"; 168 | return str; 169 | } 170 | 171 | if( "AUDUSD" == symbol_received ) { 172 | str=ip_adress+":"+prefixPort+"25"; 173 | return str; 174 | } 175 | 176 | if( "GBPUSD" == symbol_received ) { 177 | str=ip_adress+":"+prefixPort+"26"; 178 | return str; 179 | } 180 | 181 | if( "USDCHF" == symbol_received ) { 182 | str=ip_adress+":"+prefixPort+"27"; 183 | return str; 184 | } 185 | 186 | if( "USDJPY" == symbol_received ) { 187 | str=ip_adress+":"+prefixPort+"28"; 188 | return str; 189 | } 190 | 191 | return(str); 192 | 193 | } 194 | //+------------------------------------------------------------------+ 195 | //| BookEvent function | 196 | //+------------------------------------------------------------------+ 197 | void OnBookEvent(const string &symbol) 198 | { 199 | // Print("Book event for: "+symbol); 200 | //--- select the symbol 201 | if(symbol==_Symbol) 202 | { 203 | //--- array of the DOM structures 204 | MqlBookInfo last_bookArray[]; 205 | 206 | 207 | //--- get the book 208 | if(MarketBookGet(_Symbol,last_bookArray)) 209 | { 210 | 211 | JSONArray* jaTicks = new JSONArray(); 212 | 213 | //--- process book data 214 | for(int idx=0;idx>> DEBUG: In ",__FUNCTION__,"(",__FILE__,":",__LINE__,") [", msg, "]") 114 | #else 115 | #define Debug(msg) 116 | #endif 117 | //+------------------------------------------------------------------+ 118 | -------------------------------------------------------------------------------- /MQL5/Include/Zmq/Context.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Context.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #include "Common.mqh" 10 | #include "SocketOptions.mqh" 11 | 12 | //--- Context options 13 | #define ZMQ_IO_THREADS 1 14 | #define ZMQ_MAX_SOCKETS 2 15 | #define ZMQ_SOCKET_LIMIT 3 16 | #define ZMQ_THREAD_PRIORITY 3 17 | #define ZMQ_THREAD_SCHED_POLICY 4 18 | #define ZMQ_MAX_MSGSZ 5 19 | 20 | //--- Default for new contexts 21 | #define ZMQ_IO_THREADS_DFLT 1 22 | #define ZMQ_MAX_SOCKETS_DFLT 1023 23 | #define ZMQ_THREAD_PRIORITY_DFLT -1 24 | #define ZMQ_THREAD_SCHED_POLICY_DFLT -1 25 | 26 | #import "libzmq.dll" 27 | intptr_t zmq_ctx_new(void); 28 | int zmq_ctx_term(intptr_t context); 29 | int zmq_ctx_shutdown(intptr_t context); 30 | int zmq_ctx_set(intptr_t context,int option,int optval); 31 | int zmq_ctx_get(intptr_t context,int option); 32 | #import 33 | //+------------------------------------------------------------------+ 34 | //| Wraps a 0MZ context | 35 | //+------------------------------------------------------------------+ 36 | class Context 37 | { 38 | private: 39 | intptr_t m_ref; 40 | protected: 41 | int get(int option) {return zmq_ctx_get(m_ref,option);} 42 | bool set(int option,int optval) {return 0==zmq_ctx_set(m_ref,option,optval);} 43 | public: 44 | Context() {m_ref=zmq_ctx_new();} 45 | ~Context() {if(0!=zmq_ctx_term(m_ref)){Debug("failed to terminate context");}} 46 | // for better cooperation between objects 47 | intptr_t ref() const {return m_ref;} 48 | bool shutdown() {return 0==zmq_ctx_shutdown(m_ref);} 49 | 50 | int getIoThreads() {return get(ZMQ_IO_THREADS);} 51 | void setIoThreads(int value) {if(!set(ZMQ_IO_THREADS,value)){Debug("failed to set ZMQ_IO_THREADS");}} 52 | 53 | int getMaxSockets() {return get(ZMQ_MAX_SOCKETS);} 54 | void setMaxSockets(int value) {if(!set(ZMQ_MAX_SOCKETS,value)){Debug("failed to set ZMQ_MAX_SOCKETS");}} 55 | 56 | int getMaxMessageSize() {return get(ZMQ_MAX_MSGSZ);} 57 | void setMaxMessageSize(int value) {if(!set(ZMQ_MAX_MSGSZ,value)){Debug("failed to set ZMQ_MAX_MSGSZ");}} 58 | 59 | int getSocketLimit() {return get(ZMQ_SOCKET_LIMIT);} 60 | 61 | int getIpv6Options() {return get(ZMQ_IPV6);} 62 | void setIpv6Options(int value) {if(!set(ZMQ_IPV6,value)){Debug("failed to set ZMQ_IPV6");}} 63 | 64 | bool isBlocky() {return 1==get(ZMQ_BLOCKY);} 65 | void setBlocky(bool value) {if(!set(ZMQ_BLOCKY,value?1:0)){Debug("failed to set ZMQ_BLOCKY");}} 66 | 67 | //--- Following options is not supported on windows 68 | void setSchedulingPolicy(int value) {/*ZMQ_THREAD_SCHED_POLICY*/} 69 | void setThreadPriority(int value) {/*ZMQ_THREAD_PRIORITY*/} 70 | }; 71 | //+------------------------------------------------------------------+ 72 | -------------------------------------------------------------------------------- /MQL5/Include/Zmq/Errno.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Errno.mqh | 3 | //+------------------------------------------------------------------+ 4 | 5 | // Following error codes come from Microsoft CRT header errno.h 6 | 7 | // Error codes 8 | #define EPERM 1 9 | #define ENOENT 2 10 | #define ESRCH 3 11 | #define EINTR 4 12 | #define EIO 5 13 | #define ENXIO 6 14 | #define E2BIG 7 15 | #define ENOEXEC 8 16 | #define EBADF 9 17 | #define ECHILD 10 18 | #define EAGAIN 11 19 | #define ENOMEM 12 20 | #define EACCES 13 21 | #define EFAULT 14 22 | #define EBUSY 16 23 | #define EEXIST 17 24 | #define EXDEV 18 25 | #define ENODEV 19 26 | #define ENOTDIR 20 27 | #define EISDIR 21 28 | #define ENFILE 23 29 | #define EMFILE 24 30 | #define ENOTTY 25 31 | #define EFBIG 27 32 | #define ENOSPC 28 33 | #define ESPIPE 29 34 | #define EROFS 30 35 | #define EMLINK 31 36 | #define EPIPE 32 37 | #define EDOM 33 38 | #define EDEADLK 36 39 | #define ENAMETOOLONG 38 40 | #define ENOLCK 39 41 | #define ENOSYS 40 42 | #define ENOTEMPTY 41 43 | 44 | // Error codes used in the Secure CRT functions 45 | #define EINVAL 22 46 | #define ERANGE 34 47 | #define EILSEQ 42 48 | #define STRUNCATE 80 49 | 50 | // Support EDEADLOCK for compatibility with older Microsoft C versions 51 | #define EDEADLOCK EDEADLK 52 | 53 | // POSIX Supplement 54 | #define EALREADY 103 55 | #define EBADMSG 104 56 | #define ECANCELED 105 57 | #define EDESTADDRREQ 109 58 | #define EIDRM 111 59 | #define EISCONN 113 60 | #define ELOOP 114 61 | #define ENODATA 120 62 | #define ENOLINK 121 63 | #define ENOMSG 122 64 | #define ENOPROTOOPT 123 65 | #define ENOSR 124 66 | #define ENOSTR 125 67 | #define ENOTRECOVERABLE 127 68 | #define EOPNOTSUPP 130 69 | #define EOTHER 131 70 | #define EOVERFLOW 132 71 | #define EOWNERDEAD 133 72 | #define EPROTO 134 73 | #define EPROTOTYPE 136 74 | #define ETIME 137 75 | #define ETXTBSY 139 76 | #define EWOULDBLOCK 140 77 | 78 | // Following error codes come from zmq.h 79 | // 0MQ errors 80 | #define ZMQ_HAUSNUMERO 156384712 81 | 82 | #define ENOTSUP (ZMQ_HAUSNUMERO + 1) 83 | #define EPROTONOSUPPORT (ZMQ_HAUSNUMERO + 2) 84 | #define ENOBUFS (ZMQ_HAUSNUMERO + 3) 85 | #define ENETDOWN (ZMQ_HAUSNUMERO + 4) 86 | #define EADDRINUSE (ZMQ_HAUSNUMERO + 5) 87 | #define EADDRNOTAVAIL (ZMQ_HAUSNUMERO + 6) 88 | #define ECONNREFUSED (ZMQ_HAUSNUMERO + 7) 89 | #define EINPROGRESS (ZMQ_HAUSNUMERO + 8) 90 | #define ENOTSOCK (ZMQ_HAUSNUMERO + 9) 91 | #define EMSGSIZE (ZMQ_HAUSNUMERO + 10) 92 | #define EAFNOSUPPORT (ZMQ_HAUSNUMERO + 11) 93 | #define ENETUNREACH (ZMQ_HAUSNUMERO + 12) 94 | #define ECONNABORTED (ZMQ_HAUSNUMERO + 13) 95 | #define ECONNRESET (ZMQ_HAUSNUMERO + 14) 96 | #define ENOTCONN (ZMQ_HAUSNUMERO + 15) 97 | #define ETIMEDOUT (ZMQ_HAUSNUMERO + 16) 98 | #define EHOSTUNREACH (ZMQ_HAUSNUMERO + 17) 99 | #define ENETRESET (ZMQ_HAUSNUMERO + 18) 100 | 101 | // Native 0MQ error codes 102 | #define EFSM (ZMQ_HAUSNUMERO + 51) 103 | #define ENOCOMPATPROTO (ZMQ_HAUSNUMERO + 52) 104 | #define ETERM (ZMQ_HAUSNUMERO + 53) 105 | #define EMTHREAD (ZMQ_HAUSNUMERO + 54) 106 | //+------------------------------------------------------------------+ 107 | -------------------------------------------------------------------------------- /MQL5/Include/Zmq/Socket.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Socket.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | 11 | #include "Common.mqh" 12 | #include "Context.mqh" 13 | #include "SocketOptions.mqh" 14 | #include "ZmqMsg.mqh" 15 | //--- fd is SOCKET on Win32, which is defined as UINT_PTR 16 | struct zmq_pollitem_t 17 | { 18 | intptr_t socket; 19 | uintptr_t fd; 20 | short events; 21 | short revents; 22 | }; 23 | 24 | //--- Socket types 25 | #define ZMQ_PAIR 0 26 | #define ZMQ_PUB 1 27 | #define ZMQ_SUB 2 28 | #define ZMQ_REQ 3 29 | #define ZMQ_REP 4 30 | #define ZMQ_DEALER 5 31 | #define ZMQ_ROUTER 6 32 | #define ZMQ_PULL 7 33 | #define ZMQ_PUSH 8 34 | #define ZMQ_XPUB 9 35 | #define ZMQ_XSUB 10 36 | #define ZMQ_STREAM 11 37 | 38 | //--- Message options 39 | #define ZMQ_MORE 1 40 | #define ZMQ_SRCFD 2 // Deprecated 41 | #define ZMQ_SHARED 3 42 | 43 | //--- Send/recv options 44 | #define ZMQ_DONTWAIT 1 45 | #define ZMQ_SNDMORE 2 46 | 47 | //--- Socket transport events (TCP, IPC and TIPC only) 48 | #define ZMQ_EVENT_CONNECTED 0x0001 49 | #define ZMQ_EVENT_CONNECT_DELAYED 0x0002 50 | #define ZMQ_EVENT_CONNECT_RETRIED 0x0004 51 | #define ZMQ_EVENT_LISTENING 0x0008 52 | #define ZMQ_EVENT_BIND_FAILED 0x0010 53 | #define ZMQ_EVENT_ACCEPTED 0x0020 54 | #define ZMQ_EVENT_ACCEPT_FAILED 0x0040 55 | #define ZMQ_EVENT_CLOSED 0x0080 56 | #define ZMQ_EVENT_CLOSE_FAILED 0x0100 57 | #define ZMQ_EVENT_DISCONNECTED 0x0200 58 | #define ZMQ_EVENT_MONITOR_STOPPED 0x0400 59 | #define ZMQ_EVENT_ALL 0xFFFF 60 | 61 | //--- I/O multiplexing 62 | #define ZMQ_POLLIN 1 63 | #define ZMQ_POLLOUT 2 64 | // We only use 0MQ sockets on Windows 65 | // So POLLERR and POLLPRI is of no use 66 | #define ZMQ_POLLERR 4 67 | #define ZMQ_POLLPRI 8 68 | 69 | #define ZMQ_POLLITEMS_DFLT 16 70 | 71 | #import "libzmq.dll" 72 | //+------------------------------------------------------------------+ 73 | //| Sockets | 74 | //+------------------------------------------------------------------+ 75 | intptr_t zmq_socket(intptr_t context,int type); 76 | int zmq_close(intptr_t s); 77 | int zmq_bind(intptr_t s,const char &addr[]); 78 | int zmq_connect(intptr_t s,const char &addr[]); 79 | int zmq_unbind(intptr_t s,const char &addr[]); 80 | int zmq_disconnect(intptr_t s,const char &addr[]); 81 | int zmq_send(intptr_t s,const uchar &buf[],size_t len,int flags); 82 | int zmq_send_const(intptr_t s,const uchar &buf[],size_t len,int flags); 83 | int zmq_recv(intptr_t s,uchar &buf[],size_t len,int flags); 84 | int zmq_socket_monitor(intptr_t s,const char &addr[],int events); 85 | //+------------------------------------------------------------------+ 86 | //| Message | 87 | //+------------------------------------------------------------------+ 88 | int zmq_msg_send(zmq_msg_t &msg,intptr_t s,int flags); 89 | int zmq_msg_recv(zmq_msg_t &msg,intptr_t s,int flags); 90 | //+------------------------------------------------------------------+ 91 | //| I/O multiplexing | 92 | //+------------------------------------------------------------------+ 93 | int zmq_poll(zmq_pollitem_t &items[],int nitems,long timeout); 94 | //+------------------------------------------------------------------+ 95 | //| Message proxying | 96 | //+------------------------------------------------------------------+ 97 | int zmq_proxy(intptr_t frontend_ref,intptr_t backend_ref,intptr_t capture_ref); 98 | int zmq_proxy_steerable(intptr_t frontend_ref,intptr_t backend_ref,intptr_t capture_ref,intptr_t control_ref); 99 | #import 100 | //+------------------------------------------------------------------+ 101 | //| Wraps a 0MQ socket | 102 | //+------------------------------------------------------------------+ 103 | class Socket: public SocketOptions 104 | { 105 | public: 106 | //--- it is not recommended to use this constructor directly: use Context factory methods instead 107 | Socket(const Context &ctx,int type):SocketOptions(zmq_socket(ctx.ref(),type)){} 108 | virtual ~Socket() {if(0!=zmq_close(m_ref)){Debug(StringFormat("Failed to close socket 0x%0X",m_ref));}} 109 | 110 | // for better cooperation between objects 111 | intptr_t ref() const {return m_ref;} 112 | 113 | bool valid() const {return m_ref!=0;} 114 | 115 | //--- see Zmq::error() if any of the following command failed 116 | //--- connection management 117 | bool bind(string addr); 118 | bool unbind(string addr); 119 | bool connect(string addr); 120 | bool disconnect(string addr); 121 | 122 | //--- send and receive packets 123 | bool recv(uchar &buf[],bool nowait=false); 124 | bool send(const uchar &buf[],bool nowait=false,bool more=false); 125 | bool sendConst(const uchar &buf[],bool nowait=false,bool more=false); 126 | 127 | bool send(ZmqMsg &msg,bool nowait=false,bool more=false); 128 | string recv(ZmqMsg &msg,bool nowait=false); 129 | 130 | void register(zmq_pollitem_t &pollitem,bool read=false,bool write=false); 131 | void register(zmq_pollitem_t &pollitems[],int index,bool read=false,bool write=false); 132 | 133 | //--- monitor socket events 134 | bool monitor(string addr,int events); 135 | 136 | //--- proxy 137 | static bool proxy(Socket *frontend,Socket *backend,Socket *capture); 138 | static bool proxySteerable(Socket *frontend,Socket *backend,Socket *capture,Socket *control); 139 | 140 | //--- poll 141 | static int poll(zmq_pollitem_t &arr[],long timeout); 142 | }; 143 | //+------------------------------------------------------------------+ 144 | //| | 145 | //+------------------------------------------------------------------+ 146 | bool Socket::bind(string addr) 147 | { 148 | char arr[]; 149 | StringToUtf8(addr,arr); 150 | bool res=(0==zmq_bind(m_ref,arr)); 151 | ArrayFree(arr); 152 | return res; 153 | } 154 | //+------------------------------------------------------------------+ 155 | //| | 156 | //+------------------------------------------------------------------+ 157 | bool Socket::unbind(string addr) 158 | { 159 | char arr[]; 160 | StringToUtf8(addr,arr); 161 | bool res=(0==zmq_unbind(m_ref,arr)); 162 | ArrayFree(arr); 163 | return res; 164 | } 165 | //+------------------------------------------------------------------+ 166 | //| | 167 | //+------------------------------------------------------------------+ 168 | bool Socket::connect(string addr) 169 | { 170 | char arr[]; 171 | StringToUtf8(addr,arr); 172 | bool res=(0==zmq_connect(m_ref,arr)); 173 | ArrayFree(arr); 174 | return res; 175 | } 176 | //+------------------------------------------------------------------+ 177 | //| | 178 | //+------------------------------------------------------------------+ 179 | bool Socket::disconnect(string addr) 180 | { 181 | char arr[]; 182 | StringToUtf8(addr,arr); 183 | bool res=(0==zmq_disconnect(m_ref,arr)); 184 | ArrayFree(arr); 185 | return res; 186 | } 187 | //+------------------------------------------------------------------+ 188 | //| | 189 | //+------------------------------------------------------------------+ 190 | bool Socket::recv(uchar &buf[],bool nowait=false) 191 | { 192 | Print("recv func 1"); 193 | int options=0; 194 | if(nowait) options|=ZMQ_DONTWAIT; 195 | return 0==zmq_recv(m_ref,buf,ArraySize(buf),options); 196 | } 197 | //+------------------------------------------------------------------+ 198 | //| | 199 | //+------------------------------------------------------------------+ 200 | bool Socket::send(const uchar &buf[],bool nowait=false,bool more=false) 201 | { 202 | int options=0; 203 | if(nowait) options|=ZMQ_DONTWAIT; 204 | if(more) options|=ZMQ_SNDMORE; 205 | return 0==zmq_send(m_ref,buf,ArraySize(buf),options); 206 | } 207 | //+------------------------------------------------------------------+ 208 | //| | 209 | //+------------------------------------------------------------------+ 210 | bool Socket::sendConst(const uchar &buf[],bool nowait=false,bool more=false) 211 | { 212 | int options=0; 213 | if(nowait) options|=ZMQ_DONTWAIT; 214 | if(more) options|=ZMQ_SNDMORE; 215 | return 0==zmq_send_const(m_ref,buf,ArraySize(buf),options); 216 | } 217 | //+------------------------------------------------------------------+ 218 | //| Send a zmq_msg_t through a socket | 219 | //+------------------------------------------------------------------+ 220 | bool Socket::send(ZmqMsg &msg,bool nowait=false,bool more=false) 221 | { 222 | int flags=0; 223 | if(nowait) flags|=ZMQ_DONTWAIT; 224 | if(more) flags|=ZMQ_SNDMORE; 225 | return -1!=zmq_msg_send(msg,m_ref,flags); 226 | } 227 | 228 | string Socket::recv(ZmqMsg &msg,bool nowait=false) 229 | { 230 | 231 | int flags=0; 232 | string message = ""; 233 | if(nowait) flags|=ZMQ_DONTWAIT; 234 | 235 | if( zmq_msg_recv(msg,m_ref,flags) ) { 236 | message = _ptr2str(zmq_msg_data(msg)); 237 | } 238 | return message; 239 | } 240 | 241 | //+------------------------------------------------------------------+ 242 | //| | 243 | //+------------------------------------------------------------------+ 244 | bool Socket::monitor(string addr,int events) 245 | { 246 | uchar str[]; 247 | StringToUtf8(addr,str); 248 | bool res=(0==zmq_socket_monitor(m_ref,str,events)); 249 | ArrayFree(str); 250 | return res; 251 | } 252 | //+------------------------------------------------------------------+ 253 | //| | 254 | //+------------------------------------------------------------------+ 255 | void Socket::register(zmq_pollitem_t &pollitem,bool read=false,bool write=false) 256 | { 257 | ZeroMemory(pollitem); 258 | pollitem.socket=m_ref; 259 | if(read) pollitem.events|=ZMQ_POLLIN; 260 | if(write) pollitem.events|=ZMQ_POLLOUT; 261 | } 262 | //+------------------------------------------------------------------+ 263 | //| | 264 | //+------------------------------------------------------------------+ 265 | void Socket::register(zmq_pollitem_t &pollitems[],int index,bool read=false,bool write=false) 266 | { 267 | ZeroMemory(pollitems[index]); 268 | pollitems[index].socket=m_ref; 269 | if(read) pollitems[index].events|=ZMQ_POLLIN; 270 | if(write) pollitems[index].events|=ZMQ_POLLOUT; 271 | } 272 | //+------------------------------------------------------------------+ 273 | //| | 274 | //+------------------------------------------------------------------+ 275 | bool Socket::proxy(Socket *frontend,Socket *backend,Socket *capture) 276 | { 277 | intptr_t frontend_ref= CheckPointer(frontend)==POINTER_DYNAMIC?frontend.ref():0; 278 | intptr_t backend_ref = CheckPointer(backend)==POINTER_DYNAMIC?backend.ref():0; 279 | intptr_t capture_ref=CheckPointer(capture)==POINTER_DYNAMIC?capture.ref():0; 280 | return 0==zmq_proxy(frontend_ref, backend_ref, capture_ref); 281 | } 282 | //+------------------------------------------------------------------+ 283 | //| | 284 | //+------------------------------------------------------------------+ 285 | bool Socket::proxySteerable(Socket *frontend,Socket *backend,Socket *capture,Socket *control) 286 | { 287 | intptr_t frontend_ref= CheckPointer(frontend)==POINTER_DYNAMIC?frontend.ref():0; 288 | intptr_t backend_ref = CheckPointer(backend)==POINTER_DYNAMIC?backend.ref():0; 289 | intptr_t capture_ref=CheckPointer(capture)==POINTER_DYNAMIC?capture.ref():0; 290 | intptr_t control_ref=CheckPointer(control)==POINTER_DYNAMIC?control.ref():0; 291 | return 0==zmq_proxy_steerable(frontend_ref, backend_ref, capture_ref, control_ref); 292 | } 293 | //+------------------------------------------------------------------+ 294 | //| | 295 | //+------------------------------------------------------------------+ 296 | int Socket::poll(zmq_pollitem_t &arr[],long timeout) 297 | { 298 | return zmq_poll(arr,ArraySize(arr),timeout); 299 | } 300 | //+------------------------------------------------------------------+ 301 | 302 | //+------------------------------------------------------------------+ 303 | //| Receive a zmq_msg_t from a socket | 304 | //+------------------------------------------------------------------+ 305 | #import "kernel32.dll" 306 | int lstrlenA(int); 307 | void RtlMoveMemory(uchar & arr[], int, int); 308 | int LocalFree(int); // May need to be changed depending on how the DLL allocates memory 309 | #import 310 | 311 | string _ptr2str(int recvPtr) { 312 | // Get the length of the string 313 | int mssgLen = lstrlenA(recvPtr); 314 | // if message length is 0, leave. 315 | if(mssgLen<1){ 316 | return(""); 317 | } 318 | //else z_trace("mssgLen: "+mssgLen); 319 | // Create a uchar[] array whose size is the string length (plus null terminator) 320 | uchar stringChar[]; 321 | ArrayResize(stringChar, mssgLen+1); 322 | 323 | // Use the Win32 API to copy the string from the block returned by the DLL 324 | // into the uchar[] array 325 | RtlMoveMemory(stringChar, recvPtr, mssgLen+1); 326 | // Convert the uchar[] array to a message string 327 | string mssg = CharArrayToString(stringChar); 328 | // Free the string memory returned by the DLL. This step can be removed but, without it, 329 | // there will be a memory leak. 330 | // The correct method for freeing the string *depends on how the DLL allocated the memory* 331 | // The following assumes that the DLL has used LocalAlloc (or an indirect equivalent). If not, 332 | // then the following line may not fix the leak, and may even cause a crash. 333 | //LocalFree(recvPtr); 334 | return mssg; 335 | } -------------------------------------------------------------------------------- /MQL5/Include/Zmq/SocketOptions.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Socket.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | 11 | #include "Common.mqh" 12 | 13 | #import "libzmq.dll" 14 | // We can overload the same function for different data types 15 | // as in the C level the optval paramter is just a pointer 16 | #define SOCKOPT_OVERLOAD_ARRAY(TYPE) \ 17 | int zmq_setsockopt(intptr_t s,int option,const TYPE &optval[],\ 18 | size_t optvallen);\ 19 | int zmq_getsockopt(intptr_t s,int option,TYPE &optval[],\ 20 | size_t &optvallen);\ 21 | 22 | #define SOCKOPT_OVERLOAD(TYPE) \ 23 | int zmq_setsockopt(intptr_t s,int option,const TYPE &optval,\ 24 | size_t optvallen);\ 25 | int zmq_getsockopt(intptr_t s,int option,TYPE &optval,\ 26 | size_t &optvallen);\ 27 | 28 | SOCKOPT_OVERLOAD_ARRAY(uchar) 29 | SOCKOPT_OVERLOAD(long) 30 | SOCKOPT_OVERLOAD(ulong) 31 | SOCKOPT_OVERLOAD(int) 32 | SOCKOPT_OVERLOAD(uint) 33 | #import 34 | 35 | // Socket options 36 | #define ZMQ_AFFINITY 4 37 | #define ZMQ_IDENTITY 5 38 | #define ZMQ_SUBSCRIBE 6 39 | #define ZMQ_UNSUBSCRIBE 7 40 | #define ZMQ_RATE 8 41 | #define ZMQ_RECOVERY_IVL 9 42 | #define ZMQ_SNDBUF 11 43 | #define ZMQ_RCVBUF 12 44 | #define ZMQ_RCVMORE 13 45 | #define ZMQ_FD 14 46 | #define ZMQ_EVENTS 15 47 | #define ZMQ_TYPE 16 48 | #define ZMQ_LINGER 17 49 | #define ZMQ_RECONNECT_IVL 18 50 | #define ZMQ_BACKLOG 19 51 | #define ZMQ_RECONNECT_IVL_MAX 21 52 | #define ZMQ_MAXMSGSIZE 22 53 | #define ZMQ_SNDHWM 23 54 | #define ZMQ_RCVHWM 24 55 | #define ZMQ_MULTICAST_HOPS 25 56 | #define ZMQ_RCVTIMEO 27 57 | #define ZMQ_SNDTIMEO 28 58 | #define ZMQ_LAST_ENDPOINT 32 59 | #define ZMQ_ROUTER_MANDATORY 33 60 | #define ZMQ_TCP_KEEPALIVE 34 61 | #define ZMQ_TCP_KEEPALIVE_CNT 35 62 | #define ZMQ_TCP_KEEPALIVE_IDLE 36 63 | #define ZMQ_TCP_KEEPALIVE_INTVL 37 64 | #define ZMQ_IMMEDIATE 39 65 | #define ZMQ_XPUB_VERBOSE 40 66 | #define ZMQ_ROUTER_RAW 41 67 | #define ZMQ_IPV6 42 68 | #define ZMQ_MECHANISM 43 69 | #define ZMQ_PLAIN_SERVER 44 70 | #define ZMQ_PLAIN_USERNAME 45 71 | #define ZMQ_PLAIN_PASSWORD 46 72 | #define ZMQ_CURVE_SERVER 47 73 | #define ZMQ_CURVE_PUBLICKEY 48 74 | #define ZMQ_CURVE_SECRETKEY 49 75 | #define ZMQ_CURVE_SERVERKEY 50 76 | #define ZMQ_PROBE_ROUTER 51 77 | #define ZMQ_REQ_CORRELATE 52 78 | #define ZMQ_REQ_RELAXED 53 79 | #define ZMQ_CONFLATE 54 80 | #define ZMQ_ZAP_DOMAIN 55 81 | #define ZMQ_ROUTER_HANDOVER 56 82 | #define ZMQ_TOS 57 83 | #define ZMQ_CONNECT_RID 61 84 | #define ZMQ_GSSAPI_SERVER 62 85 | #define ZMQ_GSSAPI_PRINCIPAL 63 86 | #define ZMQ_GSSAPI_SERVICE_PRINCIPAL 64 87 | #define ZMQ_GSSAPI_PLAINTEXT 65 88 | #define ZMQ_HANDSHAKE_IVL 66 89 | #define ZMQ_SOCKS_PROXY 68 90 | #define ZMQ_XPUB_NODROP 69 91 | #define ZMQ_BLOCKY 70 92 | #define ZMQ_XPUB_MANUAL 71 93 | #define ZMQ_XPUB_WELCOME_MSG 72 94 | #define ZMQ_STREAM_NOTIFY 73 95 | #define ZMQ_INVERT_MATCHING 74 96 | #define ZMQ_HEARTBEAT_IVL 75 97 | #define ZMQ_HEARTBEAT_TTL 76 98 | #define ZMQ_HEARTBEAT_TIMEOUT 77 99 | #define ZMQ_XPUB_VERBOSER 78 100 | #define ZMQ_CONNECT_TIMEOUT 79 101 | #define ZMQ_TCP_MAXRT 80 102 | #define ZMQ_THREAD_SAFE 81 103 | #define ZMQ_MULTICAST_MAXTPDU 84 104 | #define ZMQ_VMCI_BUFFER_SIZE 85 105 | #define ZMQ_VMCI_BUFFER_MIN_SIZE 86 106 | #define ZMQ_VMCI_BUFFER_MAX_SIZE 87 107 | #define ZMQ_VMCI_CONNECT_TIMEOUT 88 108 | #define ZMQ_USE_FD 89 109 | //+------------------------------------------------------------------+ 110 | //| A dedicated class to get/set socket options | 111 | //+------------------------------------------------------------------+ 112 | class SocketOptions 113 | { 114 | protected: 115 | intptr_t m_ref; 116 | 117 | #define SOCKOPT_WRAP_ARRAY(TYPE) \ 118 | bool setOption(int option,const TYPE &value[],size_t len) {return 0==zmq_setsockopt(m_ref,option,value,len);}\ 119 | bool getOption(int option,TYPE &value[],size_t &len) {return 0==zmq_getsockopt(m_ref,option,value,len);} 120 | 121 | #define SOCKOPT_WRAP(TYPE) \ 122 | bool setOption(int option,TYPE value) {return 0==zmq_setsockopt(m_ref,option,value,sizeof(TYPE));}\ 123 | bool getOption(int option,TYPE &value) {size_t s=sizeof(TYPE); return 0==zmq_getsockopt(m_ref,option,value,s);} 124 | 125 | SOCKOPT_WRAP_ARRAY(uchar) 126 | SOCKOPT_WRAP(int) 127 | SOCKOPT_WRAP(uint) 128 | SOCKOPT_WRAP(long) 129 | SOCKOPT_WRAP(ulong) 130 | 131 | bool setStringOption(int option,string value,bool ending=true); 132 | bool getStringOption(int option,string &value,size_t length=1024); 133 | SocketOptions(intptr_t ref):m_ref(ref){} 134 | public: 135 | //--- option templates 136 | //--- various integer options 137 | #define SOCKOPT_GET(TYPE, NAME, MACRO) \ 138 | bool get##NAME(TYPE &value) {return getOption(MACRO,value);} 139 | #define SOCKOPT_SET(TYPE, NAME, MACRO) \ 140 | bool set##NAME(TYPE value) {return setOption(MACRO,value);} 141 | #define SOCKOPT(TYPE,NAME,MACRO) \ 142 | SOCKOPT_GET(TYPE,NAME,MACRO) \ 143 | SOCKOPT_SET(TYPE,NAME,MACRO) 144 | 145 | //--- boolean options 146 | #define SOCKOPT_GET_BOOL(NAME, MACRO) \ 147 | bool is##NAME(bool &value) {int v; bool res=getOption(MACRO,v); value=(v==1);return res;} 148 | #define SOCKOPT_SET_BOOL(NAME, MACRO) \ 149 | bool set##NAME(bool value) {return setOption(MACRO,value?1:0);} 150 | #define SOCKOPT_BOOL(NAME,MACRO) \ 151 | SOCKOPT_GET_BOOL(NAME,MACRO) \ 152 | SOCKOPT_SET_BOOL(NAME,MACRO) 153 | 154 | //--- null-terminated string options 155 | #define SOCKOPT_GET_NTSTR(NAME,MACRO) \ 156 | bool get##NAME(string &value) {return getStringOption(MACRO,value);} 157 | #define SOCKOPT_SET_NTSTR(NAME,MACRO) \ 158 | bool set##NAME(string value) {return setStringOption(MACRO,value);} 159 | #define SOCKOPT_NTSTR(NAME,MACRO) \ 160 | SOCKOPT_GET_NTSTR(NAME,MACRO) \ 161 | SOCKOPT_SET_NTSTR(NAME,MACRO) 162 | 163 | //--- bytes array or string converted options 164 | #define SOCKOPT_SET_BYTES(OptionName,Macro) \ 165 | bool set##OptionName(const uchar &value[]) {return setOption(Macro,value,(size_t)ArraySize(value));} \ 166 | bool set##OptionName(string value) {return setStringOption(Macro,value,false);} 167 | #define SOCKOPT_GET_BYTES(OptionName,Macro,InitSize) \ 168 | bool get##OptionName(uchar &value[]) {size_t len=(size_t)InitSize; ArrayResize(value,(int)len); bool res=getOption(Macro,value,len); if(res){ArrayResize(value,(int)len);}return res;} \ 169 | bool get##OptionName(string &value) {return getStringOption(Macro,value,InitSize);} 170 | #define SOCKOPT_BYTES(OptionName,Macro,InitSize) \ 171 | SOCKOPT_SET_BYTES(OptionName,Macro) \ 172 | SOCKOPT_GET_BYTES(OptionName,Macro,InitSize) 173 | 174 | //--- for curve key 175 | #define SOCKOPT_CURVE_KEY(KeyType,Macro) \ 176 | bool getCurve##KeyType##Key(uchar &key[32]) {size_t len=32; return getOption(Macro,key,len);} \ 177 | bool getCurve##KeyType##Key(string &key) {return getStringOption(Macro,key,41);} \ 178 | bool setCurve##KeyType##Key(const uchar &key[32]) {return setOption(Macro,key,32);} \ 179 | bool setCurve##KeyType##Key(string key) {return setStringOption(Macro,key);} 180 | 181 | SOCKOPT_GET(int,Type,ZMQ_TYPE) 182 | SOCKOPT(ulong,Affinity,ZMQ_AFFINITY) //64bit bitmask 183 | SOCKOPT(int,BackLog,ZMQ_BACKLOG) // number of connections 184 | SOCKOPT(int,Timeout,ZMQ_CONNECT_TIMEOUT) // milliseconds 185 | SOCKOPT_GET_BOOL(ThreadSafe,ZMQ_THREAD_SAFE) 186 | 187 | SOCKOPT_SET_BOOL(Conflate,ZMQ_CONFLATE) // only for ZMQ_PULL, ZMQ_PUSH, ZMQ_SUB, ZMQ_PUB, ZMQ_DEALER types 188 | 189 | SOCKOPT_GET(int,Events,ZMQ_EVENTS); // bitmask of ZMQ_POLLIN, ZMQ_POLLOUT 190 | 191 | SOCKOPT_GET(uintptr_t,FileDescriptor,ZMQ_FD) 192 | 193 | SOCKOPT_GET(int,Mechanism,ZMQ_MECHANISM) // current security mechanism 194 | 195 | //--- plain 196 | SOCKOPT_NTSTR(PlainUsername,ZMQ_PLAIN_USERNAME) 197 | SOCKOPT_NTSTR(PlainPassword,ZMQ_PLAIN_PASSWORD) 198 | SOCKOPT_BOOL(PlainServer,ZMQ_PLAIN_SERVER) 199 | 200 | //--- gssapi: this is not supported in this binding. Following methods will FAIL if you invoke them 201 | SOCKOPT_BOOL(GssApiPlainText,ZMQ_GSSAPI_PLAINTEXT) 202 | SOCKOPT_BOOL(GssApiServer,ZMQ_GSSAPI_SERVER) 203 | SOCKOPT_NTSTR(GssApiPrincipal,ZMQ_GSSAPI_PRINCIPAL) 204 | SOCKOPT_NTSTR(GssApiServicePrincipal,ZMQ_GSSAPI_SERVICE_PRINCIPAL) 205 | 206 | //--- curve 207 | //SOCKOPT_CURVE_KEY(Public,ZMQ_CURVE_PUBLICKEY) 208 | //SOCKOPT_CURVE_KEY(Secret,ZMQ_CURVE_SECRETKEY) 209 | //SOCKOPT_CURVE_KEY(Server,ZMQ_CURVE_SERVERKEY) 210 | 211 | SOCKOPT_SET_BOOL(CurveServer,ZMQ_CURVE_SERVER) 212 | 213 | SOCKOPT_GET_NTSTR(LastEndpoint,ZMQ_LAST_ENDPOINT) 214 | 215 | SOCKOPT(int,HandshakeInterval,ZMQ_HANDSHAKE_IVL) // milliseconds 216 | SOCKOPT_SET(int,HeartbeatInterval,ZMQ_HEARTBEAT_IVL) // milliseconds 217 | SOCKOPT_SET(int,HeartbeatTimeout,ZMQ_HEARTBEAT_TIMEOUT) // milliseconds 218 | SOCKOPT_SET(int,HeartbeatTTL,ZMQ_HEARTBEAT_TTL) // milliseconds 219 | 220 | SOCKOPT_BOOL(Immediate,ZMQ_IMMEDIATE) 221 | SOCKOPT_BOOL(Ipv6,ZMQ_IPV6) //--- ZMQ_IPV4ONLY is deprecated, use this instead 222 | SOCKOPT(int,Linger,ZMQ_LINGER) // milliseconds 223 | SOCKOPT(long,MaxMessageSize,ZMQ_MAXMSGSIZE) 224 | 225 | //--- multicast 226 | SOCKOPT(int,MulticastHops,ZMQ_MULTICAST_HOPS) // hops 227 | SOCKOPT(int,MulticastMaxTPDU,ZMQ_MULTICAST_MAXTPDU) // bytes 228 | SOCKOPT(int,MulticastRate,ZMQ_RATE) // kilobits per second 229 | SOCKOPT(int,RecoveryInterval,ZMQ_RECOVERY_IVL) // multicast recovery interval 230 | 231 | //--- there is a problem here: FileDescriptor should be SOCKET type on Windows, 232 | //--- while in the zmq doc it is a int. Possible error in the doc 233 | SOCKOPT(uintptr_t,UseFileDescriptor,ZMQ_USE_FD) 234 | 235 | SOCKOPT_SET_BOOL(ProbeRouter,ZMQ_PROBE_ROUTER) // only for ZMQ_ROUTER, ZMQ_DEALER, ZMQ_REQ 236 | 237 | SOCKOPT(int,ReceiveBuffer,ZMQ_RCVBUF) // bytes 238 | SOCKOPT(int,ReceiveHighWaterMark,ZMQ_RCVHWM) // messages 239 | SOCKOPT(int,ReceiveTimeout,ZMQ_RCVTIMEO) // milliseconds 240 | SOCKOPT(int,SendBuffer,ZMQ_SNDBUF) // bytes 241 | SOCKOPT(int,SendHighWaterMark,ZMQ_SNDHWM) // messages 242 | SOCKOPT(int,SendTimout,ZMQ_SNDTIMEO) 243 | 244 | SOCKOPT_GET_BOOL(ReceiveMore,ZMQ_RCVMORE) 245 | 246 | SOCKOPT(int,ReconnectInterval,ZMQ_RECONNECT_IVL) // milliseconds 247 | SOCKOPT(int,ReconnectIntervalMax,ZMQ_RECONNECT_IVL_MAX) // milliseconds 248 | 249 | //--- only for ZMQ_REQ 250 | SOCKOPT_SET_BOOL(RequestCorrelated,ZMQ_REQ_CORRELATE) 251 | SOCKOPT_SET_BOOL(RequestRelaxed,ZMQ_REQ_RELAXED) 252 | 253 | //--- only for ZMQ_SUB 254 | SOCKOPT_SET_BYTES(Subscribe,ZMQ_SUBSCRIBE) 255 | SOCKOPT_SET_BYTES(Unsubscribe,ZMQ_UNSUBSCRIBE) 256 | 257 | //--- convenience methods 258 | bool subscribe(string channel) {return setSubscribe(channel);} 259 | bool unsubscribe(string channel) {return setUnsubscribe(channel);} 260 | 261 | //--- only for ZMQ_XSUB 262 | SOCKOPT_BOOL(XpubVerbose,ZMQ_XPUB_VERBOSE) 263 | SOCKOPT_BOOL(XpubVerboser,ZMQ_XPUB_VERBOSER) 264 | SOCKOPT_BOOL(XpubManual,ZMQ_XPUB_MANUAL) 265 | SOCKOPT_BOOL(XpubNoDrop,ZMQ_XPUB_NODROP) // also for ZMQ_PUB 266 | SOCKOPT_SET_BYTES(XpubWelcomeMessage,ZMQ_XPUB_WELCOME_MSG) 267 | 268 | SOCKOPT_BOOL(InvertMatching,ZMQ_INVERT_MATCHING) //--- only for ZMQ_PUB, ZMQ_XPUB, ZMQ_SUB 269 | 270 | //--- only for ZMQ_ROUTER 271 | SOCKOPT_SET_BOOL(RouterHandover,ZMQ_ROUTER_HANDOVER) 272 | SOCKOPT_SET_BOOL(RouterMandatory,ZMQ_ROUTER_MANDATORY) 273 | SOCKOPT_SET_BOOL(RouterRaw,ZMQ_ROUTER_RAW) 274 | 275 | //--- only for ZMQ_STREAM 276 | SOCKOPT_SET_BOOL(StreamNotify,ZMQ_STREAM_NOTIFY) 277 | 278 | //--- only for ZMQ_ROUTER, ZMQ_STREAM 279 | SOCKOPT_SET_BYTES(ConnectRid,ZMQ_CONNECT_RID) 280 | 281 | //--- only for ZMQ_REP, ZMQ_REQ, ZMQ_ROUTER, ZMQ_DEALER 282 | SOCKOPT_BYTES(Identity,ZMQ_IDENTITY,255) 283 | 284 | //--- tcp 285 | SOCKOPT(int,TcpKeepAlive,ZMQ_TCP_KEEPALIVE) 286 | SOCKOPT(int,TcpKeepAliveCount,ZMQ_TCP_KEEPALIVE_CNT) 287 | SOCKOPT(int,TcpKeepAliveIdle,ZMQ_TCP_KEEPALIVE_IDLE) 288 | SOCKOPT(int,TcpKeepAliveInterval,ZMQ_TCP_KEEPALIVE_INTVL) 289 | SOCKOPT(int,TcpMaxRetransmitTimeout,ZMQ_TCP_MAXRT) 290 | 291 | SOCKOPT(int,TypeOfService,ZMQ_TOS) // IP_TOS 292 | 293 | //--- ZMQ_TCP_ACCEPT_FILTER 294 | //--- ZMQ_IPC_FILTER_GID 295 | //--- ZMQ_IPC_FILTER_PID 296 | //--- ZMQ_IPC_FILTER_UID 297 | //--- are deprecated in favor of ZAP API and ip address whitelisting/blacklisting 298 | SOCKOPT_NTSTR(ZapDomain,ZMQ_ZAP_DOMAIN) 299 | 300 | //--- only for vmci transport 301 | SOCKOPT(ulong,VmciBufferSize,ZMQ_VMCI_BUFFER_SIZE) // bytes 302 | SOCKOPT(ulong,VmciBufferMinSize,ZMQ_VMCI_BUFFER_MIN_SIZE) // bytes 303 | SOCKOPT(ulong,VmciBufferMaxSize,ZMQ_VMCI_BUFFER_MAX_SIZE) // bytes 304 | SOCKOPT(int,VmciConnectTimeout,ZMQ_VMCI_CONNECT_TIMEOUT) // milliseconds 305 | }; 306 | //+------------------------------------------------------------------+ 307 | //| The option value is a string with predefined byte length | 308 | //| | 309 | //| If it is a NULL-terminated string without predefined length, | 310 | //| The situation is tricky: we do not know the length of the option | 311 | //| value beforehand, but the function does not return the correct | 312 | //| one, either. So the only option is to guess. | 313 | //| | 314 | //| Here we adopt the solution of the Java binding. We just guess | 315 | //| that the length of a NULL-terminated string option is less than | 316 | //| 1024. So hopefully, it is the case. | 317 | //+------------------------------------------------------------------+ 318 | bool SocketOptions::getStringOption(int option,string &value,size_t length) 319 | { 320 | char buf[]; 321 | ArrayResize(buf,(int)length); 322 | bool res=getOption(option,buf,length); 323 | if(res) 324 | { 325 | value=StringFromUtf8(buf); 326 | } 327 | ArrayFree(buf); 328 | return res; 329 | } 330 | //+------------------------------------------------------------------+ 331 | //| The ending means that the converted buffer contains the ending | 332 | //| null. | 333 | //+------------------------------------------------------------------+ 334 | bool SocketOptions::setStringOption(int option,const string value,bool ending) 335 | { 336 | char buf[]; 337 | StringToUtf8(value,buf,ending); 338 | int len = ArraySize(buf); 339 | bool res=setOption(option,buf,len); 340 | ArrayFree(buf); 341 | return res; 342 | } 343 | //+------------------------------------------------------------------+ 344 | -------------------------------------------------------------------------------- /MQL5/Include/Zmq/Z85.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Z85.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | 11 | #include "Common.mqh" 12 | 13 | #import "libzmq.dll" 14 | // Encode data with Z85 encoding. Returns 0(NULL) if failed 15 | intptr_t zmq_z85_encode(char &str[],const uchar &data[],size_t size); 16 | 17 | // Decode data with Z85 encoding. Returns 0(NULL) if failed 18 | intptr_t zmq_z85_decode(uchar &dest[],const char &str[]); 19 | 20 | // Generate z85-encoded public and private keypair with tweetnacl/libsodium 21 | int zmq_curve_keypair(char &z85_public_key[],char &z85_secret_key[]); 22 | 23 | // Derive the z85-encoded public key from the z85-encoded secret key 24 | int zmq_curve_public(char &z85_public_key[],const char &z85_secret_key[]); 25 | #import 26 | //+------------------------------------------------------------------+ 27 | //| Z85 encoding/decoding | 28 | //+------------------------------------------------------------------+ 29 | class Z85 30 | { 31 | public: 32 | static bool encode(string &secret,const uchar &data[]); 33 | static bool decode(const string secret,uchar &data[]); 34 | 35 | static string encode(string data); 36 | static string decode(string secret); 37 | 38 | static bool generateKeyPair(uchar &publicKey[],uchar &secretKey[]); 39 | static bool derivePublic(uchar &publicKey[],const uchar &secretKey[]); 40 | 41 | static bool generateKeyPair(string &publicKey,string &secretKey); 42 | static string derivePublic(const string secretKey); 43 | }; 44 | //+------------------------------------------------------------------+ 45 | //| data must have size multiple of 4 | 46 | //+------------------------------------------------------------------+ 47 | bool Z85::encode(string &secret,const uchar &data[]) 48 | { 49 | int size=ArraySize(data); 50 | if(size%4 != 0) return false; 51 | 52 | char str[]; 53 | ArrayResize(str,(int)(1.25*size+1)); 54 | 55 | intptr_t res=zmq_z85_encode(str,data,size); 56 | if(res == 0) return false; 57 | secret = StringFromUtf8(str); 58 | return true; 59 | } 60 | //+------------------------------------------------------------------+ 61 | //| secret must be multiples of 5 | 62 | //+------------------------------------------------------------------+ 63 | bool Z85::decode(const string secret,uchar &data[]) 64 | { 65 | int len=StringLen(secret); 66 | if(len%5 != 0) return false; 67 | 68 | char str[]; 69 | StringToUtf8(secret,str); 70 | ArrayResize(data,(int)(0.8*len)); 71 | return 0 != zmq_z85_decode(data,str); 72 | } 73 | //+------------------------------------------------------------------+ 74 | //| data length should be multiples of 4 and only ascii is supported | 75 | //+------------------------------------------------------------------+ 76 | string Z85::encode(string data) 77 | { 78 | char str[]; 79 | StringToUtf8(data,str,false); 80 | string res; 81 | if(encode(res,str)) 82 | return res; 83 | else 84 | return ""; 85 | } 86 | //+------------------------------------------------------------------+ 87 | //| secret must be multiples of 5 | 88 | //+------------------------------------------------------------------+ 89 | string Z85::decode(string secret) 90 | { 91 | uchar data[]; 92 | decode(secret,data); 93 | return StringFromUtf8(data); 94 | } 95 | //+------------------------------------------------------------------+ 96 | //| | 97 | //+------------------------------------------------------------------+ 98 | bool Z85::generateKeyPair(uchar &publicKey[],uchar &secretKey[]) 99 | { 100 | ArrayResize(publicKey,41); 101 | ArrayResize(secretKey,41); 102 | return 0==zmq_curve_keypair(publicKey, secretKey); 103 | } 104 | //+------------------------------------------------------------------+ 105 | //| | 106 | //+------------------------------------------------------------------+ 107 | bool Z85::derivePublic(uchar &publicKey[],const uchar &secretKey[]) 108 | { 109 | ArrayResize(publicKey,41); 110 | return 0==zmq_curve_public(publicKey, secretKey); 111 | } 112 | //+------------------------------------------------------------------+ 113 | //| | 114 | //+------------------------------------------------------------------+ 115 | bool Z85::generateKeyPair(string &publicKey,string &secretKey) 116 | { 117 | uchar sec[],pub[]; 118 | bool res=generateKeyPair(pub,sec); 119 | if(res) 120 | { 121 | secretKey=StringFromUtf8(sec); 122 | publicKey=StringFromUtf8(pub); 123 | } 124 | ArrayFree(sec); 125 | ArrayFree(pub); 126 | return res; 127 | } 128 | //+------------------------------------------------------------------+ 129 | //| | 130 | //+------------------------------------------------------------------+ 131 | string Z85::derivePublic(const string secrect) 132 | { 133 | uchar sec[],pub[]; 134 | StringToUtf8(secrect,sec); 135 | derivePublic(pub,sec); 136 | string pubstr=StringFromUtf8(pub); 137 | ArrayFree(sec); 138 | ArrayFree(pub); 139 | return pubstr; 140 | } 141 | //+------------------------------------------------------------------+ 142 | -------------------------------------------------------------------------------- /MQL5/Include/Zmq/Zmq.mqh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL5/Include/Zmq/Zmq.mqh -------------------------------------------------------------------------------- /MQL5/Include/Zmq/ZmqMsg.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| ZmqMsg.mqh | 3 | //| Copyright 2017, Hitback | 4 | //| mauro@hitback.us | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Hitback" 7 | #property link "mauro@hitback.us" 8 | #property version "1.00" 9 | #property strict 10 | #include "Common.mqh" 11 | //+------------------------------------------------------------------+ 12 | //| 0MQ Message struct | 13 | //+------------------------------------------------------------------+ 14 | // align sizeof(intptr_t) 15 | // = 8 on 64bit 16 | // = 4 on 32bit 17 | // hopefully MetaQuotes do malloc structs 18 | // aligned on pointer address boundaries 19 | struct zmq_msg_t 20 | { 21 | uchar _[64]; 22 | }; 23 | 24 | #import "libzmq.dll" 25 | int zmq_msg_init(zmq_msg_t &msg); 26 | int zmq_msg_init_size(zmq_msg_t &msg,size_t size); 27 | // As mt4 can not provide a zmq_free_fn, and can not let 28 | // zmq library own the array data, copying is always needed. 29 | // Therefore this function will not be used by this binding. 30 | // int zmq_msg_init_data(zmq_msg_t &msg,uchar &data[], 31 | // int size,int ffn,int hint); 32 | int zmq_msg_close(zmq_msg_t &msg); 33 | int zmq_msg_move(zmq_msg_t &dest,zmq_msg_t &src); 34 | int zmq_msg_copy(zmq_msg_t &dest,zmq_msg_t &src); 35 | // char * 36 | intptr_t zmq_msg_data(zmq_msg_t &msg); 37 | int zmq_msg_size(zmq_msg_t &msg); 38 | int zmq_msg_more(zmq_msg_t &msg); 39 | int zmq_msg_get(zmq_msg_t &msg,int property); 40 | int zmq_msg_set(zmq_msg_t &msg,int property,int optval); 41 | // const char * 42 | intptr_t zmq_msg_gets(zmq_msg_t &msg,const char &property[]); 43 | #import 44 | //+------------------------------------------------------------------+ 45 | //| Wraps a zmq_msg_t | 46 | //+------------------------------------------------------------------+ 47 | struct ZmqMsg: public zmq_msg_t 48 | { 49 | protected: 50 | int get(int property) {return zmq_msg_get(this,property);} 51 | bool set(int property,int value) {return 0==zmq_msg_set(this,property,value);} 52 | intptr_t data() {return zmq_msg_data(this);} 53 | public: 54 | ZmqMsg() {zmq_msg_init(this);} 55 | ZmqMsg(int size) {if(0!=zmq_msg_init_size(this,size)){Debug("Failed to init size msg: insufficient space");}} 56 | ZmqMsg(string data,bool nullterminated=false); 57 | ~ZmqMsg() {if(0!=zmq_msg_close(this)){Debug("Failed to close msg");}} 58 | 59 | size_t size() {return zmq_msg_size(this);} 60 | 61 | void getData(uchar &data[]); 62 | string getData(); 63 | void setData(const uchar &data[]); 64 | 65 | bool more() {return 1==zmq_msg_more(this);} 66 | 67 | bool copy(ZmqMsg &msg) {return 0 == zmq_msg_copy(this, msg);} 68 | bool move(ZmqMsg &msg) {return 0 == zmq_msg_move(this, msg);} 69 | 70 | string meta(const string property); 71 | }; 72 | //+------------------------------------------------------------------+ 73 | //| Initialize a utf-8 string message | 74 | //+------------------------------------------------------------------+ 75 | ZmqMsg::ZmqMsg(string data,bool nullterminated) 76 | { 77 | uchar array[]; 78 | StringToUtf8(data,array,nullterminated); 79 | int size=ArraySize(array); 80 | zmq_msg_init_size(this,size); 81 | setData(array); 82 | } 83 | //+------------------------------------------------------------------+ 84 | //| Get message data as bytes array | 85 | //+------------------------------------------------------------------+ 86 | void ZmqMsg::getData(uchar &data[]) 87 | { 88 | size_t size=size(); 89 | intptr_t src=data(); 90 | ArrayResize(data,(int)size); 91 | ArrayFromPointer(data,src); 92 | } 93 | //+------------------------------------------------------------------+ 94 | //| Get message data as utf-8 string | 95 | //+------------------------------------------------------------------+ 96 | string ZmqMsg::getData() 97 | { 98 | size_t size=size(); 99 | intptr_t psz=data(); 100 | return StringFromUtf8Pointer(psz,(int)size); 101 | } 102 | //+------------------------------------------------------------------+ 103 | //| copy data to message internal storage | 104 | //+------------------------------------------------------------------+ 105 | void ZmqMsg::setData(const uchar &data[]) 106 | { 107 | intptr_t dest=data(); 108 | ArrayToPointer(data,dest); 109 | } 110 | //+------------------------------------------------------------------+ 111 | //| Wraps zmq_msg_gets: get metadata associated with the msg | 112 | //+------------------------------------------------------------------+ 113 | string ZmqMsg::meta(const string property) 114 | { 115 | uchar buf[]; 116 | StringToUtf8(property,buf); 117 | intptr_t ref=zmq_msg_gets(this,buf); 118 | ArrayFree(buf); 119 | return StringFromUtf8Pointer(ref); 120 | } 121 | //+------------------------------------------------------------------+ 122 | -------------------------------------------------------------------------------- /MQL5/Include/hash.mqh: -------------------------------------------------------------------------------- 1 | // $Id: hash.mqh 125 2014-03-03 08:38:32Z ydrol $ 2 | #ifndef YDROL_HASH_MQH 3 | #define YDROL_HASH_MQH 4 | 5 | //#property strict 6 | 7 | /* 8 | This is losely ported from a C version I have which was in turn modified from hashtable.c by Christopher Clark. 9 | Copyright (C) 2014, Andrew Lord (NICKNAME=lordy) 10 | Copyright (C) 2002, 2004 Christopher Clark 11 | 12 | 2014/02/21 - Readded PrimeNumber sizes and auto rehashing when load factor hit. 13 | */ 14 | 15 | 16 | 17 | /// Any value stored in a Hash must be a subclass of HashValue 18 | class HashValue { 19 | }; 20 | 21 | /// Linked list of values - there will be one list for each hash value 22 | class HashEntry { 23 | public: 24 | string _key; 25 | HashValue * _val; 26 | HashEntry *_next; 27 | 28 | HashEntry() { 29 | _key=NULL; 30 | _val=NULL; 31 | _next=NULL; 32 | } 33 | 34 | HashEntry(string key,HashValue* val) { 35 | _key=key; 36 | _val=val; 37 | _next=NULL; 38 | } 39 | 40 | ~HashEntry() { 41 | } 42 | }; 43 | 44 | /// Convenience class for storing strings as hash values. 45 | class HashString : public HashValue { 46 | private: 47 | string val; 48 | public: 49 | HashString(string v) { val=v;} 50 | string getVal() { return val; } 51 | }; 52 | 53 | /// Convenience class for storing doubles as hash values. 54 | class HashDouble : public HashValue { 55 | private: 56 | double val; 57 | public: 58 | HashDouble(double v) { val=v;} 59 | double getVal() { return val; } 60 | }; 61 | 62 | /// Convenience class for storing ints as hash values. 63 | class HashInt : public HashValue { 64 | private: 65 | int val; 66 | public: 67 | HashInt(int v) { val=v;} 68 | int getVal() { return val; } 69 | }; 70 | 71 | /// Convenience class for storing longs as hash values. 72 | class HashLong : public HashValue { 73 | private: 74 | long val; 75 | public: 76 | HashLong(datetime v) { val=v;} 77 | long getVal() { return val; } 78 | 79 | }; 80 | 81 | /// Convenience class for storing datetimes as hash values. 82 | class HashDatetime : public HashValue { 83 | private: 84 | datetime val; 85 | public: 86 | HashDatetime(datetime v) { val=v;} 87 | datetime getVal() { return val; } 88 | }; 89 | 90 | /// 91 | /// Hash class allows objects to be stored in a table index by strings. 92 | /// the stored Objects must be a sub class of the HashValue class. 93 | /// 94 | /// There are some convenience classes to hold atomic types as values HashString,HashDouble,HashInt 95 | /// 96 | ///EXAMPLE: 97 | /// 98 | ///
 99 | /// class myClass: public HashValue {
100 | ///   public: int v;
101 | ///   myClass(int a) { v = a;}
102 | /// };
103 | ///
104 | /// // Create the objects as needed
105 | ///
106 | ///      myClass *a = new myClass(1);
107 | ///      myClass *b = new myClass(2);
108 | ///      myClass *c = new myClass(3);
109 | ///
110 | /// // Then to insert into hash etc.
111 | ///
112 | ///      Hash* h = new Hash(193,true); 
113 | ///      // 'true' means when the hash will adopt the values and delete them when they are removed from the hash or when the hash is deleted.
114 | ///
115 | ///      h.hPut("a",a);
116 | ///      h.hPut("b",b);
117 | ///      h.hPut("c",c);
118 | ///
119 | ///      myClass *d = h.hGet("b");
120 | ///
121 | ///      etc.
122 | ///
123 | /// // Iterate over hash
124 | ///    HashLoop *l
125 | ///    for (l = new HashLoop(h) ; l.hasNext() ; l.next()  ) {
126 | ///        string key = l.key();
127 | ///        MyClass *c = l.val();
128 | ///    }
129 | ///    delete l;
130 | ///
131 | ///    // Delete from hash - This will also delete 'a' because we set the 'adopt' flag on the hash.
132 | ///    h.hDel("a");
133 | ///
134 | ///    //Delete the hash - this will also delete 'b' and 'c' because of the adopt flag.
135 | ///    delete h;
136 | /// 
137 | class Hash : public HashValue { 138 | 139 | private: 140 | /// Number of slots in the hashtable. 141 | /// this should be approx number of elements to store. Depending on hash algorithm 142 | /// it may optimally be a prime or a power of two etc. but probably not important 143 | /// for MQL4 performance. A future optimisation might be to move the hashcode function to a DLL?? 144 | uint _hashSlots; 145 | 146 | /// Number of elements at which hash will get resized. 147 | int _resizeThreshold; 148 | 149 | /// number of things in the hash 150 | int _hashEntryCount; 151 | 152 | /// an array of linked lists (HashEntry). one for each hash value. 153 | /// To store an object against a string(key) - get the string hashcode, then insert pair (key,val) into the linked list for that hashcode. 154 | /// To fetch an object against a string(key) - get the string hashcode, get linked-list at that hashcode index, then search for the key and return the val. 155 | HashEntry* _buckets[]; 156 | 157 | /// If true the hash will free(delete) values as they are removed, or at cleanup. 158 | bool _adoptValues; 159 | 160 | int _errCode; 161 | string _errText; 162 | 163 | void init(uint size,bool adoptValues) 164 | { 165 | _hashSlots = 0; 166 | _hashEntryCount = 0; 167 | clearError(); 168 | setAdoptValues(adoptValues); 169 | 170 | rehash(size); 171 | } 172 | 173 | // Hash table distribution is better when size is prime, eg if hash function procduces numbers 174 | // that are multiples of x, then there may be grouping occuring around gcd(x,slots) gcd(2x,slots) etc 175 | // using a prime size helps spread the distribution. 176 | uint size2prime(uint size) { 177 | int pmax=ArraySize(_primes); 178 | for(int p=0 ; p= size) { 180 | return _primes[p]; 181 | } 182 | } 183 | return size; 184 | } 185 | 186 | /// Primes that approx double in size, used for hash table sizes to avoid gcd causing bunching 187 | static uint _primes[]; 188 | 189 | /// After reviewing quite a few hash functions I settled on the one below. 190 | /// http://www.cse.yorku.ca/~oz/hash.html 191 | /// this is the bottleneck function. Shame mql hash no default hash method for objects. 192 | uint hash(string s) 193 | { 194 | 195 | uchar c[]; 196 | uint h = 0; 197 | 198 | if (s != NULL) { 199 | h = 5381; 200 | int n = StringToCharArray(s,c); 201 | for(int i = 0 ; i < n ; i++ ) { 202 | h = ((h << 5 ) + h ) + c[i]; 203 | } 204 | } 205 | return h % _hashSlots; 206 | } 207 | void clearError() { 208 | setError(0,""); 209 | } 210 | void setError(int e,string m) { 211 | _errCode = e; 212 | _errText = m; 213 | //error((string)e,m); 214 | } 215 | 216 | public: 217 | 218 | /// Constructor: Create a Hash Object 219 | Hash() { 220 | init(17,true); 221 | } 222 | 223 | 224 | /// Constructor: Create a Hash Object 225 | /// @param adoptValues : If true the hash destructor will delete all dynamically allocated hash values. 226 | Hash(bool adoptValues) { 227 | init(17,adoptValues); 228 | } 229 | 230 | /// Constructor: Create a Hash Object 231 | /// @param size : Approximate size (actual size will be a larger prime number close to a power of 2) 232 | /// @param adoptValues : If true the hash destructor will delete all dynamically allocated hash values. 233 | Hash(int size,bool adoptValues) { 234 | init(size,adoptValues); 235 | } 236 | 237 | ~Hash() { 238 | 239 | // Free entries. 240 | for(uint i = 0 ; i< _hashSlots ; i++) { 241 | HashEntry *nextEntry = NULL; 242 | for(HashEntry *entry = _buckets[i] ; entry!= NULL ; entry = nextEntry ) 243 | { 244 | nextEntry = entry._next; 245 | 246 | if (_adoptValues && entry._val != NULL && CheckPointer(entry._val) == POINTER_DYNAMIC ) { 247 | delete entry._val; 248 | } 249 | delete entry; 250 | } 251 | _buckets[i] = NULL; 252 | } 253 | } 254 | 255 | /// Return any error that has occured. This should be used when 256 | /// retriving values in a Hash that may contain NULLs. hGet() 257 | /// methods can return NULL if not found, in which case getErrorCode 258 | /// will be set. 259 | int getErrCode() { 260 | return _errCode; 261 | } 262 | /// Return text of the error message. 263 | string getErrText() { 264 | return _errText; 265 | } 266 | 267 | /// If true the hash destructor will delete all dynamically allocated hash values. 268 | void setAdoptValues(bool v) { 269 | _adoptValues = v; 270 | } 271 | 272 | /// True if the hash destructor will delete all dynamically allocated hash values. 273 | bool getAdoptValues() { 274 | return _adoptValues; 275 | } 276 | 277 | private: 278 | uint _foundIndex; // After find() is called is set to hashindex for name whether found or not. 279 | HashEntry* _foundEntry; // After find() is called is set to the HashEntry that contains the key. 280 | HashEntry* _foundPrev; // After find() is called is set to the HashEntry before the entry 281 | // (could use double linked list but requires more memory). 282 | 283 | /// Look for the required entry for key 'name' true if found. 284 | bool find(string keyName) { 285 | 286 | //Alert("finding"); 287 | bool found = false; 288 | 289 | // Get the index using the hashcode of the string 290 | _foundIndex = hash(keyName); 291 | 292 | 293 | if (_foundIndex>_hashSlots ) { 294 | 295 | setError(1,"hGet: bad hashIndex="+(string)_foundIndex+" size "+(string)_hashSlots); 296 | 297 | } else { 298 | 299 | // Search the linked list determined by the index. 300 | 301 | for(HashEntry *e = _buckets[_foundIndex] ; e != NULL ; e = e._next ) { 302 | if (e._key == keyName) { 303 | _foundEntry = e; 304 | found=true; 305 | break; 306 | } 307 | // Track the item before the target item in case deleting from single linked list. 308 | _foundPrev = e; 309 | } 310 | } 311 | 312 | return found; 313 | } 314 | 315 | public: 316 | 317 | /// This is used by the HashLoop class to get start of LinkedList at bucket[i] 318 | HashEntry*getEntry(int i) { 319 | return _buckets[i]; 320 | } 321 | 322 | /// Return the number of slots/buckets (not number of elements) 323 | uint getSlots() { 324 | return _hashSlots; 325 | } 326 | /// Return the number of elements in the Hash 327 | int getCount() { 328 | return _hashEntryCount; 329 | } 330 | 331 | /// Change the hash size and re-allocate values to new buckets. 332 | bool rehash(uint newSize) { 333 | bool ret = false; 334 | HashEntry* oldTable[]; 335 | 336 | uint oldSize = _hashSlots; 337 | newSize = size2prime(newSize); 338 | //info("rehashing from "+(string)_hashSlots+" to "+(string)newSize+" "+(string)GetTickCount()); 339 | 340 | if (newSize <= getSlots()) { 341 | setError(2,"rehash "+(string)newSize+" <= "+(string)_hashSlots); 342 | } else if (ArrayResize(_buckets,newSize) != newSize) { 343 | setError(3,"unable to resize "); 344 | } else if (ArrayResize(oldTable,oldSize) != oldSize) { 345 | setError(4,"unable to resize old copy "); 346 | } else { 347 | //Copy old table. 348 | uint i; 349 | for(i = 0 ; i < oldSize ; i++ ) oldTable[i] = _buckets[i]; 350 | // Init new entries - not sure if MQL does this anyway 351 | for(i = 0 ; ikeyName key. This will overwrite any existing 459 | /// value. It adoptValues is set, it will also free the value if applicable. 460 | /// @param keyName : key name 461 | /// @param obj : Value to store 462 | /// @return the previous value of the key or NULL if there wasnt one 463 | HashValue *hPut(string keyName,HashValue *obj) { 464 | 465 | HashValue *ret = NULL; 466 | clearError(); 467 | 468 | if (find(keyName)) { 469 | // Return revious value 470 | ret = _foundEntry._val; 471 | /* 472 | // Replace entry contents 473 | if (_adoptValues && _foundEntry._val != NULL && CheckPointer(_foundEntry._val) == POINTER_DYNAMIC ) { 474 | delete _foundEntry._val; 475 | } 476 | */ 477 | _foundEntry._val = obj; 478 | 479 | } else { 480 | // Insert new entry at head of list 481 | HashEntry* e = new HashEntry(keyName,obj); 482 | HashEntry* first = _buckets[_foundIndex]; 483 | e._next = first; 484 | _buckets[_foundIndex] = e; 485 | _hashEntryCount++; 486 | 487 | //info((string)_hashEntryCount+" vs. "+(string)_resizeThreshold); 488 | // Auto Resize if number of entries hits _resizeThreshold 489 | if (_hashEntryCount > _resizeThreshold ) { 490 | rehash(_hashSlots/2*3); // this will snap to the next prime 491 | } 492 | } 493 | return ret; 494 | } 495 | /// Store a string as hash value (HashString) 496 | /// @return the previous value of the key or NULL if there wasnt one 497 | HashValue* hPutString(string keyName,string s) { 498 | HashString *v = new HashString(s); 499 | return hPut(keyName,v); 500 | } 501 | /// Store a double as hash value (HashDouble) 502 | /// @return the previous value of the key or NULL if there wasnt one 503 | HashValue* hPutDouble(string keyName,double d) { 504 | HashDouble *v = new HashDouble(d); 505 | return hPut(keyName,v); 506 | } 507 | /// Store an int as hash value (HashInt) 508 | /// @return the previous value of the key or NULL if there wasnt one 509 | HashValue* hPutInt(string keyName,int i) { 510 | HashInt *v = new HashInt(i); 511 | return hPut(keyName,v); 512 | } 513 | 514 | /// Store a datetime as hash value (HashLong) 515 | /// @return the previous value of the key or NULL if there wasnt one 516 | HashValue* hPutLong(string keyName,long i) { 517 | HashLong *v = new HashLong(i); 518 | return hPut(keyName,v); 519 | } 520 | 521 | /// Store a datetime as hash value (HashDatetime) 522 | /// @return the previous value of the key or NULL if there wasnt one 523 | HashValue* hPutDatetime(string keyName,datetime i) { 524 | HashDatetime *v = new HashDatetime(i); 525 | return hPut(keyName,v); 526 | } 527 | 528 | /// Delete an entry from the hash. 529 | bool hDel(string keyName) { 530 | 531 | bool found = false; 532 | clearError(); 533 | 534 | if (find(keyName)) { 535 | HashEntry *next = _foundEntry._next; 536 | if (_foundPrev != NULL) { 537 | //Remove entry from the middle of the list. 538 | _foundPrev._next = next; 539 | } else { 540 | // remove from head of list 541 | _buckets[_foundIndex] = next; 542 | } 543 | 544 | if (_adoptValues && _foundEntry._val != NULL&& CheckPointer(_foundEntry._val) == POINTER_DYNAMIC) { 545 | delete _foundEntry._val; 546 | } 547 | delete _foundEntry; 548 | _hashEntryCount--; 549 | found=true; 550 | 551 | } 552 | return found; 553 | } 554 | }; 555 | uint Hash::_primes[] = { 556 | 17, 53, 97, 193, 389, 557 | 769, 1543, 3079, 6151, 558 | 12289, 24593, 49157, 98317, 559 | 196613, 393241, 786433, 1572869, 560 | 3145739, 6291469, 12582917, 25165843, 561 | 50331653, 100663319, 201326611, 402653189, 562 | 805306457, 1610612741}; 563 | 564 | /// Class to iterate over a Hash using ... 565 | ///
566 | ///   HashLoop *l
567 | ///   for (l = new HashLoop(h) ; l.hasNext() ; l.next()  ) {
568 | ///       string key = l.key();
569 | ///       MyClass *c = l.val();
570 | ///   }
571 | ///   delete l;
572 | /// 
573 | class HashLoop { 574 | private: 575 | uint _index; 576 | HashEntry *_currentEntry; 577 | Hash *_hash; 578 | 579 | public: 580 | /// Create iterator for a hash - move to first item 581 | HashLoop(Hash *h) { 582 | setHash(h); 583 | } 584 | ~HashLoop() {}; 585 | 586 | /// Clear current state and move to first item (if any). 587 | void reset() { 588 | _index=0; 589 | _currentEntry = _hash.getEntry(_index); 590 | 591 | // Move to first item 592 | if (_currentEntry == NULL) { 593 | next(); 594 | } 595 | } 596 | 597 | /// Change the hash over which to iterate. 598 | void setHash(Hash *h) { 599 | _hash = h; 600 | reset(); 601 | } 602 | 603 | /// Check if more items. 604 | bool hasNext() { 605 | bool ret = ( _currentEntry != NULL); 606 | //config("hasNext=",ret); 607 | return ret; 608 | } 609 | 610 | /// Move to next item. 611 | void next() { 612 | 613 | //config("next : index = ",_index); 614 | 615 | // Advance 616 | if (_currentEntry != NULL) { 617 | _currentEntry = _currentEntry._next; 618 | } 619 | 620 | // Keep advancing if _currentEntry is null 621 | while (_currentEntry==NULL) { 622 | _index++; 623 | if (_index >= _hash.getSlots() ) return ; 624 | _currentEntry = _hash.getEntry(_index); 625 | } 626 | } 627 | 628 | /// Return the key name of the current item. 629 | string key() { 630 | if (_currentEntry != NULL) { 631 | return _currentEntry._key; 632 | } else { 633 | return NULL; 634 | } 635 | } 636 | 637 | /// Return the value. 638 | HashValue *val() { 639 | if (_currentEntry != NULL) { 640 | return _currentEntry._val; 641 | } else { 642 | return NULL; 643 | } 644 | } 645 | 646 | /// Convenience functions for retriving int from a current HashInt entry 647 | int valInt() { 648 | return ((HashInt *)val()).getVal(); 649 | } 650 | 651 | /// Convenience functions for retriving int from a current HashString entry 652 | string valString() { 653 | return ((HashString *)val()).getVal(); 654 | } 655 | 656 | /// Convenience functions for retriving int from a current HashDouble entry 657 | double valDouble() { 658 | return ((HashDouble *)val()).getVal(); 659 | } 660 | 661 | /// Convenience functions for retriving int from a current HashLong entry 662 | long valLong() { 663 | return ((HashLong *)val()).getVal(); 664 | } 665 | /// Convenience functions for retriving int from a current HashDatetime entry 666 | datetime valDatetime() { 667 | return ((HashDatetime *)val()).getVal(); 668 | } 669 | }; 670 | 671 | 672 | #endif -------------------------------------------------------------------------------- /MQL5/Libraries/libsodium.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL5/Libraries/libsodium.dll -------------------------------------------------------------------------------- /MQL5/Libraries/libzmq.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL5/Libraries/libzmq.dll -------------------------------------------------------------------------------- /MQL5/Scripts/client.mq5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL5/Scripts/client.mq5 -------------------------------------------------------------------------------- /MQL5/Scripts/server.mq5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/MQL5/Scripts/server.mq5 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [hitback.us](https://www.hitback.us/ "Hitback") 2 | Algorithmic trading and quantitative trading platform to develop trading robots (stock markets, forex, bitcoins and options) 3 | 4 | ### 5 | 6 | This project provide [MQL4](https://www.metatrader4.com/ "Metatrader 4.") and [MQL5](https://www.metatrader5.com/ "Metatrader 5.") bindings for the [ZeroMQ](http://zeromq.org/ "ZeroMQ homepage.") networking library to an external server to create live streaming pipeline with real time data of ticks and order book changes. 7 | 8 | With ZeroMQ (http://zeromq.org/) you can: 9 | * Connect your code in any language, on any platform. 10 | * Carries messages across inproc, IPC, TCP, TIPC, multicast. 11 | * Smart patterns like pub-sub, push-pull, and router-dealer. 12 | * High-speed asynchronous I/O engines, in a tiny library. 13 | * Backed by a large and active open source community. 14 | * Supports every modern language and platform. 15 | * Build any architecture: centralized, distributed, small, or large. 16 | 17 | # Exchange side 18 | 19 | In this example we are using just two brokers [XM](https://www.xm.com/ "XM") and [FXPRO](http://www.fxpro.com/ "fxpro") for streaming the data but you can connect to an unlimit numner of brokers at the same time. 20 | 21 | ### INSTALL 22 | 23 | Recursively copy the folder MQL4 for metatrader4 over the MQL4 folder or for metatrader5 recursively copy the folder MQL5 over the MQL5 24 | 25 | ### Version notes: 26 | I'm using MetaTrader build 1000+ and ZeroMQ4.x 27 | 28 | * NOTE: when attaching to the chart make sure to select "Allow DLL Imports" and de-select "Confirm DLL Function Calls". 29 | * NOTE: If you want to use ZeroMQ different of 4.x you must compile the dll again 30 | * NOTE: Precompiled DLLs of both 64bit and 32bit ZeroMQ and libsodium are provided. If you are using MT5 32bit, use the 32bit version from `Library/MT4`. The DLLs require that you have the latest Visual C++ runtime (2015). *Note* that these DLLs are compiled from official sources, without any modification. You can compile your own if you don't trust these binaries. The `libsodium.dll` is copied from the official binary release. If you want to support security mechanisms other than `curve`, or you want to use transports like OpenPGM, you need to compile your own DLL. 31 | 32 | ## About string encoding 33 | 34 | MQL strings are Win32 UNICODE strings (basically 2-byte UTF-16). In this binding all strings are converted to utf-8 strings before sending to the dll layer. The ZmqMsg supports a constructor from MQL strings, the default is _NOT_ null-terminated. 35 | 36 | # Server side 37 | 38 | ### INSTALL 39 | 40 | Inside the Server folder there is a server with ZMQ that subscribe the brokers to get every tick and also the order book in real time. 41 | Once the ZMQ receive new ticks or any change on the order book happen, it is automatically re-streamed to [Kafka](https://kafka.apache.org/ "Kafka") / [ZeroMQ](http://www.zeromq.org/ "ZeroMQ") and [PubNub](https://www.pubnub.com/ "PubNub") and you can process this data in real time. 42 | 43 | 44 | ## Install ZMQ Ubuntu 16.04 45 | 46 | sudo apt-get install libtool pkg-config build-essential autoconf automake 47 | 48 | sudo apt-get install libzmq-dev 49 | 50 | ### Install libsodium 51 | 52 | git clone git://github.com/jedisct1/libsodium.git 53 | 54 | cd libsodium 55 | 56 | ./autogen.sh 57 | 58 | ./configure && make check 59 | 60 | sudo make install 61 | 62 | sudo ldconfig 63 | 64 | ### Install zeromq 65 | 66 | ### latest version as of this post is 4.1.2 67 | 68 | wget http://download.zeromq.org/zeromq-4.1.2.tar.gz 69 | 70 | tar -xvf zeromq-4.1.2.tar.gz 71 | 72 | cd zeromq-4.1.2 73 | 74 | ./autogen.sh 75 | 76 | ./configure && make check 77 | 78 | sudo make install 79 | 80 | sudo ldconfig 81 | 82 | ### Pushing Support 83 | * PubNub 84 | * RabbitMQ 85 | * ZeroMQ 86 | * Kafka 87 | 88 | 89 | -------------------------------------------------------------------------------- /ZMQ-SERVER/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /ZMQ-SERVER/README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricSchles/bindings-mql4-5/41bbbaa49d1c836d09a589be625b99e816c765d4/ZMQ-SERVER/README -------------------------------------------------------------------------------- /ZMQ-SERVER/app.js: -------------------------------------------------------------------------------- 1 | var mars = require('./mars'); 2 | 3 | mars.initialize(); 4 | -------------------------------------------------------------------------------- /ZMQ-SERVER/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | exchanges : { 3 | 'xm' : { 4 | name: 'xm', 5 | enabled: true, 6 | fee : 0.2 / 100, // 7 | currencies : ['USD'], 8 | pricing_server: '76.9.21.100', 9 | execution_server: '76.9.21.100', 10 | port_prefix: 20, 11 | debug: true, 12 | symbols: ['EURUSD', 'USDJPY', 'GBPUSD', 'USDCHF', 'EURGBP', 'EURJPY', 'EURCHF', 'AUDUSD', 'USDCAD', 'NZDUSD'] 13 | }, 14 | 'fxpro' : { 15 | name: 'fxpro', 16 | enabled: true, 17 | fee : 0.2 / 100, // 18 | currencies : ['USD'], 19 | pricing_server: '76.9.21.101', 20 | execution_server: '76.9.21.101', 21 | port_prefix: 40, 22 | debug: true, 23 | symbols: ['EURUSD', 'USDJPY', 'GBPUSD', 'USDCHF', 'EURGBP', 'EURJPY', 'EURCHF', 'AUDUSD', 'USDCAD', 'NZDUSD'] 24 | } 25 | } 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /ZMQ-SERVER/consumer-module.js: -------------------------------------------------------------------------------- 1 | const kafka = require('kafka-node'); 2 | const Consumer = kafka.Consumer; 3 | 4 | module.exports = { 5 | create: function create(client, topic) { 6 | return new Consumer(client, [{topic: topic, partition: 0}], {autocommit: false}); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /ZMQ-SERVER/exchanges/fxpro.js: -------------------------------------------------------------------------------- 1 | var colors = require('colors'), 2 | _ = require('underscore'), 3 | Deferred = require("promised-io/promise").Deferred, 4 | config = require('./../config'), 5 | utils = require('./../utils'), 6 | zmq = require('zeromq'), 7 | server = config.exchanges.fxpro.pricing_server, 8 | port_prefix = config.exchanges.fxpro.port_prefix, 9 | enabled = config.exchanges.fxpro.enabled, 10 | debug = config.exchanges.fxpro.debug, 11 | exchangeRef = config.exchanges.fxpro.name; 12 | 13 | module.exports = { 14 | 15 | exchangeName: config.exchanges.fxpro.name, 16 | 17 | markers: config.exchanges.fxpro.symbols, 18 | 19 | emitter: {}, 20 | 21 | hasOpenOrder: false, 22 | 23 | symbolZMQ: {}, 24 | 25 | initialize: function(emitter) { 26 | this.emitter = emitter; 27 | this.setMarket(); 28 | }, 29 | 30 | setMarket: function() { 31 | if (enabled) { 32 | this.bindEvents(); 33 | this.subscribeExchange(); 34 | } 35 | }, 36 | 37 | bindEvents: function() { 38 | _.bindAll(this, 'checkOrderStatus', 'fetchBalance', 'createOrder'); 39 | this.emitter.on(this.exchangeName + ':orderNotMatched', this.checkOrderStatus); 40 | this.emitter.on(this.exchangeName + ':orderMatched', this.fetchBalance); 41 | this.emitter.on(this.exchangeName + ':orderCreated', this.checkOrderStatus); 42 | this.emitter.on(this.exchangeName + ':orderNotCreated', this.createOrder); 43 | }, 44 | 45 | subscribeExchange: function() { 46 | 47 | _.each(this.markers, function(symbols) { 48 | 49 | if (utils.getSymbolExchangePort(symbols) > 0) { 50 | 51 | this.symbolZMQ[symbols] = zmq.socket('sub'); 52 | this.symbolZMQ[symbols].connect('tcp://' + server + ':' + port_prefix + utils.getSymbolExchangePort(symbols) + ''); 53 | this.symbolZMQ[symbols].subscribe(''); 54 | this.listeningExchange(symbols); 55 | 56 | } 57 | }, this); 58 | 59 | }, 60 | 61 | listeningExchange: function(symbols) { 62 | 63 | 64 | this.symbolZMQ[symbols].on('message', function(data) { 65 | 66 | var msg = (data.toString('utf8')); 67 | var msg_obj = JSON.parse(msg) 68 | 69 | if (typeof msg_obj === 'object') { 70 | 71 | if (debug) { 72 | console.log('Message ' + msg); 73 | } 74 | 75 | utils.emitMarketData(msg_obj, exchangeRef); 76 | 77 | } 78 | 79 | }) 80 | }, 81 | 82 | fetchBalance: function() { 83 | 84 | }, 85 | 86 | createOrder: function(market, type, rate, amount) { 87 | 88 | }, 89 | 90 | calculateProfit: function(amount, decimals) { 91 | 92 | }, 93 | 94 | calculateCost: function(amount, decimals) { 95 | 96 | }, 97 | 98 | getExchangeInfo: function() { 99 | 100 | }, 101 | 102 | checkOrderStatus: _.debounce(function() { 103 | 104 | }), 105 | 106 | populatePrices: function(data) { 107 | 108 | } 109 | }; 110 | -------------------------------------------------------------------------------- /ZMQ-SERVER/exchanges/xm.js: -------------------------------------------------------------------------------- 1 | var colors = require('colors'), 2 | _ = require('underscore'), 3 | Deferred = require("promised-io/promise").Deferred, 4 | config = require('./../config'), 5 | utils = require('./../utils'), 6 | zmq = require('zeromq'), 7 | server = config.exchanges.xm.pricing_server, 8 | port_prefix = config.exchanges.xm.port_prefix, 9 | enabled = config.exchanges.xm.enabled, 10 | debug = config.exchanges.xm.debug, 11 | exchangeRef = config.exchanges.xm.name; 12 | 13 | module.exports = { 14 | 15 | exchangeName: config.exchanges.xm.name, 16 | 17 | markers: config.exchanges.xm.symbols, 18 | 19 | emitter: {}, 20 | 21 | hasOpenOrder: false, 22 | 23 | symbolZMQ: {}, 24 | 25 | initialize: function(emitter) { 26 | this.emitter = emitter; 27 | this.setMarket(); 28 | }, 29 | 30 | setMarket: function() { 31 | if (enabled) { 32 | this.bindEvents(); 33 | this.subscribeExchange(); 34 | } 35 | }, 36 | 37 | bindEvents: function() { 38 | _.bindAll(this, 'checkOrderStatus', 'fetchBalance', 'createOrder'); 39 | this.emitter.on(this.exchangeName + ':orderNotMatched', this.checkOrderStatus); 40 | this.emitter.on(this.exchangeName + ':orderMatched', this.fetchBalance); 41 | this.emitter.on(this.exchangeName + ':orderCreated', this.checkOrderStatus); 42 | this.emitter.on(this.exchangeName + ':orderNotCreated', this.createOrder); 43 | }, 44 | 45 | subscribeExchange: function() { 46 | 47 | _.each(this.markers, function(symbols) { 48 | 49 | if (utils.getSymbolExchangePort(symbols) > 0) { 50 | 51 | this.symbolZMQ[symbols] = zmq.socket('sub'); 52 | this.symbolZMQ[symbols].connect('tcp://' + server + ':' + port_prefix + utils.getSymbolExchangePort(symbols) + ''); 53 | this.symbolZMQ[symbols].subscribe(''); 54 | this.listeningExchange(symbols); 55 | 56 | } 57 | }, this); 58 | 59 | }, 60 | 61 | listeningExchange: function(symbols) { 62 | 63 | this.symbolZMQ[symbols].on('message', function(data) { 64 | 65 | var msg = (data.toString('utf8')); 66 | var msg_obj = JSON.parse(msg) 67 | 68 | if (typeof msg_obj === 'object') { 69 | 70 | if (debug) { 71 | console.log('Message ' + msg); 72 | } 73 | 74 | utils.emitMarketData(msg_obj, exchangeRef); 75 | 76 | } 77 | 78 | }) 79 | }, 80 | 81 | fetchBalance: function() { 82 | 83 | }, 84 | 85 | createOrder: function(market, type, rate, amount) { 86 | 87 | }, 88 | 89 | calculateProfit: function(amount, decimals) { 90 | 91 | }, 92 | 93 | calculateCost: function(amount, decimals) { 94 | 95 | }, 96 | 97 | getExchangeInfo: function() { 98 | 99 | }, 100 | 101 | checkOrderStatus: _.debounce(function() { 102 | 103 | }), 104 | 105 | populatePrices: function(data) { 106 | 107 | } 108 | }; -------------------------------------------------------------------------------- /ZMQ-SERVER/kafka-module.js: -------------------------------------------------------------------------------- 1 | const kafka = require('kafka-node'); 2 | var producer = kafka.Producer, 3 | client = new kafka.Client('localhost:2181'), 4 | producer = new Producer(client); 5 | 6 | module.exports = { 7 | producer: producer, 8 | client: client 9 | }; 10 | -------------------------------------------------------------------------------- /ZMQ-SERVER/mars.js: -------------------------------------------------------------------------------- 1 | var colors = require('colors'), 2 | config = require('./config'), 3 | _ = require('underscore'), 4 | when = require('promised-io/promise').when, 5 | all = require('promised-io/promise').all, 6 | utils = require('./utils'), 7 | Deferred = require("promised-io/promise").Deferred, 8 | queueconf = require('./queueconf'), 9 | queue = require('./queue'), 10 | events = require('events'), 11 | emitter = new events.EventEmitter(); 12 | 13 | module.exports = { 14 | 15 | priceLookupCounter: 0, 16 | 17 | openTrades: [], 18 | 19 | exchangeMarkets: { 20 | 'xp': require('./exchanges/xm'), 21 | 'fxpro': require('./exchanges/fxpro') 22 | }, 23 | 24 | initialize: function() { 25 | 26 | this.bindEvents() 27 | this.initializeExchanges() 28 | this.populateValidExchanges() 29 | 30 | utils.initialize(emitter) 31 | queue.initialize() 32 | 33 | }, 34 | 35 | bindEvents: function() { 36 | _.bindAll(this, 'sendMessage') 37 | emitter.on('sendMessage', this.sendMessage) 38 | }, 39 | 40 | sendMessage: function(message) { 41 | 42 | queue.publishToQueue("forex", message) 43 | }, 44 | 45 | populateValidExchanges: function() { 46 | 47 | var exchanges_enabled = _.filter(config.exchanges, function(item) { 48 | return item.enabled == true 49 | }) 50 | 51 | this.validExchanges = {}; 52 | if (exchanges_enabled.length > 0) { 53 | this.validExchanges = exchanges_enabled 54 | } 55 | }, 56 | 57 | initializeExchanges: function() { 58 | _.each(this.exchangeMarkets, function(exchange) { 59 | exchange.initialize(emitter) 60 | }, this); 61 | } 62 | 63 | }; 64 | -------------------------------------------------------------------------------- /ZMQ-SERVER/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mars", 3 | "version": "1.0.0", 4 | "description": "https://github.com/DrawnWren/market-service/tree/master/exchanges", 5 | "main": "mars.js", 6 | "dependencies": { 7 | "kafka-node": "^1.6.0", 8 | "zeromq": "^4.2.1" 9 | }, 10 | "devDependencies": {}, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://maurodelazeri@bitbucket.org/maurodelazeri/mars.git" 17 | }, 18 | "author": "", 19 | "license": "ISC", 20 | "homepage": "https://bitbucket.org/maurodelazeri/mars#readme" 21 | } 22 | -------------------------------------------------------------------------------- /ZMQ-SERVER/queue.js: -------------------------------------------------------------------------------- 1 | var zmq = require('zeromq'), 2 | queueconf = require('./queueconf'), 3 | responder = zmq.socket('pub'), 4 | kafka = require('kafka-node'), 5 | Producer = kafka.Producer, 6 | PubNub = require('pubnub'); 7 | 8 | if (queueconf.zeromq.enabled) 9 | pubnub = new PubNub({ 10 | publishKey: queueconf.zeromq.publishKey, 11 | subscribeKey: queueconf.zeromq.subscribeKey 12 | }) 13 | 14 | var client, producer; 15 | 16 | module.exports = { 17 | 18 | initialize: function() { 19 | 20 | if (queueconf.zeromq.enabled) { 21 | responder.bind('tcp://' + queueconf.zeromq.host + ':' + queueconf.zeromq.port, function(err) { 22 | console.log("Listening") 23 | }) 24 | } 25 | 26 | if (queueconf.kafka.enabled) 27 | this.kafkaConnect() 28 | 29 | }, 30 | 31 | kafkaConnect: function() { 32 | this.client = new kafka.Client(queueconf.kafka.zookeeper_host + ":" + queueconf.kafka.zookeeper_port) 33 | this.producer = new Producer(this.client) 34 | }, 35 | 36 | publishToQueue: function(channel, data) { 37 | 38 | // PUBNUB PUBLISH 39 | if (queueconf.zeromq.pubnub) { 40 | var publishConfig = { 41 | channel: channel, 42 | message: data 43 | } 44 | 45 | pubnub.publish(publishConfig, function(status, response) { 46 | console.log(status, response); 47 | }) 48 | } 49 | 50 | // ZMQ PUBLISH 51 | if (queueconf.zeromq.enabled) 52 | responder.send([channel, data]) 53 | 54 | // KAFKA PUBLISH 55 | if (queueconf.kafka.enabled) { 56 | 57 | if (typeof data === 'object') { 58 | var payloads = [{ 59 | topic: channel, 60 | messages: JSON.stringify(data), 61 | // messages: data, 62 | partition: 0 63 | }]; 64 | 65 | this.producer.send(payloads, function(err) { 66 | if (err) { 67 | console.log('Error: ' + err); 68 | } 69 | }); 70 | } 71 | 72 | } 73 | } 74 | 75 | }; -------------------------------------------------------------------------------- /ZMQ-SERVER/queueconf.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | zeromq : { 3 | enabled: true, 4 | host: "127.0.0.1", 5 | port: 2626 6 | }, 7 | kafka : { 8 | enabled: true, 9 | zookeeper_host: "127.0.0.1", 10 | zookeeper_port: 2181 11 | }, 12 | pubnub : { 13 | enabled: true, 14 | publishKey: "pub-c-a61bb7c8-1ef7-4bdb-b178-22bdf0b953b2", 15 | subscribeKey: "sub-c-f98971e4-380a-11e7-9361-0619f8945a4f" 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /ZMQ-SERVER/utils.js: -------------------------------------------------------------------------------- 1 | var config = require('./config'), 2 | _ = require('underscore') 3 | 4 | 5 | module.exports = { 6 | 7 | emitter: {}, 8 | 9 | initialize: function (emitter) { 10 | this.emitter = emitter; 11 | }, 12 | 13 | emitMarketData: function(data,exchange) { 14 | this.emitter.emit('sendMessage',data) 15 | }, 16 | 17 | getSymbolExchangePort: function(symbol) { 18 | 19 | var selected = 0; 20 | 21 | switch (symbol) { 22 | case 'AUDCAD': 23 | selected = '02'; 24 | break; 25 | case 'AUDCHF': 26 | selected = '03'; 27 | break; 28 | case 'EURUSD': 29 | selected = '04'; 30 | break; 31 | case 'AUDJPY': 32 | selected = '05'; 33 | break; 34 | case 'AUDNZD': 35 | selected = '06'; 36 | break; 37 | case 'CADCHF': 38 | selected = '07'; 39 | break; 40 | case 'CADJPY': 41 | selected = '08'; 42 | break; 43 | case 'CHFJPY': 44 | selected = '09'; 45 | break; 46 | case 'EURAUD': 47 | selected = '10'; 48 | break; 49 | case 'EURCAD': 50 | selected = '11'; 51 | break; 52 | case 'EURCHF': 53 | selected = '12'; 54 | break; 55 | case 'EURGBP': 56 | selected = '13'; 57 | break; 58 | case 'GBPAUD': 59 | selected = '14'; 60 | break; 61 | case 'GBPCAD': 62 | selected = '15'; 63 | break; 64 | case 'GBPCHF': 65 | selected = '16'; 66 | break; 67 | case 'GBPJPY': 68 | selected = '17'; 69 | break; 70 | case 'GBPNZD': 71 | selected = '18'; 72 | break; 73 | case 'NZDCHF': 74 | selected = '19'; 75 | break; 76 | case 'NZDJPY': 77 | selected = '20'; 78 | break; 79 | case 'NZDUSD': 80 | selected = '21'; 81 | break; 82 | case 'EURNZD': 83 | selected = '22'; 84 | break; 85 | case 'USDCAD': 86 | selected = '23'; 87 | break; 88 | case 'EURJPY': 89 | selected = '24'; 90 | break; 91 | case 'AUDUSD': 92 | selected = '25'; 93 | break; 94 | case 'GBPUSD': 95 | selected = '26'; 96 | break; 97 | case 'USDCHF': 98 | selected = '27'; 99 | break; 100 | case 'USDJPY': 101 | selected = '28'; 102 | break; 103 | } 104 | 105 | return selected; 106 | } 107 | 108 | }; --------------------------------------------------------------------------------