From b38862f39939fd9af9888b7866d32978c89a1dbb Mon Sep 17 00:00:00 2001 From: Vyacheslav Kornienko Date: Thu, 26 Dec 2024 00:31:39 +0300 Subject: [PATCH] Update readme --- .idea/deployment.xml | 18 ++ .idea/sshConfigs.xml | 8 + .idea/webServers.xml | 14 + CHANGELOG.md | 22 ++ LICENSE | 21 ++ README.md | 89 ++++++ client_example.py | 153 ++++++++++ docs/mt5_reference/account_info.md | 96 ++++++ docs/mt5_reference/copy_rates_from.md | 117 ++++++++ docs/mt5_reference/copy_rates_from_pos.md | 81 +++++ docs/mt5_reference/copy_rates_range.md | 94 ++++++ docs/mt5_reference/copy_ticks_from.md | 112 +++++++ docs/mt5_reference/copy_ticks_range.md | 111 +++++++ docs/mt5_reference/history_deals_get.md | 122 ++++++++ docs/mt5_reference/history_orders_get.md | 105 +++++++ docs/mt5_reference/history_orders_total.md | 53 ++++ docs/mt5_reference/initialize.md | 82 ++++++ docs/mt5_reference/last_error.md | 62 ++++ docs/mt5_reference/login.md | 74 +++++ docs/mt5_reference/market_book_add.md | 66 +++++ docs/mt5_reference/market_book_get.md | 74 +++++ docs/mt5_reference/market_book_release.md | 70 +++++ docs/mt5_reference/order_calc_margin.md | 97 ++++++ docs/mt5_reference/order_calc_profit.md | 99 +++++++ docs/mt5_reference/order_check.md | 160 ++++++++++ docs/mt5_reference/order_send.md | 137 +++++++++ docs/mt5_reference/orders_get.md | 98 +++++++ docs/mt5_reference/orders_total.md | 52 ++++ docs/mt5_reference/positions_get.md | 122 ++++++++ docs/mt5_reference/shutdown.md | 47 +++ docs/mt5_reference/symbol_info.md | 99 +++++++ docs/mt5_reference/symbol_info_tick.md | 74 +++++ docs/mt5_reference/symbol_select.md | 58 ++++ docs/mt5_reference/symbols_get.md | 79 +++++ docs/mt5_reference/symbols_total.md | 48 +++ docs/mt5_reference/terminal_info.md | 86 ++++++ docs/mt5_reference/version.md | 63 ++++ generate_proto.sh | 10 +- generated/__init__.py | 0 imp/__init__.py | 0 mt5_grpc_proto/MANIFEST.in | 8 + mt5_grpc_proto/Readme.md | 23 ++ mt5_grpc_proto/mt5_grpc_proto/__init__.py | 32 ++ mt5_grpc_proto/mt5_grpc_proto/account_pb2.py | 43 +++ .../mt5_grpc_proto/account_pb2_grpc.py | 101 +++++++ mt5_grpc_proto/mt5_grpc_proto/common_pb2.py | 48 +++ .../mt5_grpc_proto/common_pb2_grpc.py | 143 +++++++++ mt5_grpc_proto/mt5_grpc_proto/deal_pb2.py | 43 +++ .../mt5_grpc_proto/deal_pb2_grpc.py | 101 +++++++ .../mt5_grpc_proto/history_orders_pb2.py | 48 +++ .../mt5_grpc_proto/history_orders_pb2_grpc.py | 145 +++++++++ .../mt5_grpc_proto/initialize_pb2.py | 49 ++++ .../mt5_grpc_proto/initialize_pb2_grpc.py | 186 ++++++++++++ .../mt5_grpc_proto/market_book_pb2.py | 53 ++++ .../mt5_grpc_proto/market_book_pb2_grpc.py | 189 ++++++++++++ .../mt5_grpc_proto/market_data_pb2.py | 68 +++++ .../mt5_grpc_proto/market_data_pb2_grpc.py | 277 ++++++++++++++++++ .../mt5_grpc_proto/order_calc_pb2.py | 45 +++ .../mt5_grpc_proto/order_calc_pb2_grpc.py | 145 +++++++++ .../mt5_grpc_proto/order_check_pb2.py | 44 +++ .../mt5_grpc_proto/order_check_pb2_grpc.py | 101 +++++++ mt5_grpc_proto/mt5_grpc_proto/order_pb2.py | 48 +++ .../mt5_grpc_proto/order_pb2_grpc.py | 145 +++++++++ mt5_grpc_proto/mt5_grpc_proto/position_pb2.py | 48 +++ .../mt5_grpc_proto/position_pb2_grpc.py | 145 +++++++++ .../mt5_grpc_proto/symbol_info_pb2.py | 44 +++ .../mt5_grpc_proto/symbol_info_pb2_grpc.py | 101 +++++++ .../mt5_grpc_proto/symbol_info_tick_pb2.py | 44 +++ .../symbol_info_tick_pb2_grpc.py | 101 +++++++ mt5_grpc_proto/mt5_grpc_proto/symbols_pb2.py | 49 ++++ .../mt5_grpc_proto/symbols_pb2_grpc.py | 189 ++++++++++++ mt5_grpc_proto/mt5_grpc_proto/terminal_pb2.py | 41 +++ .../mt5_grpc_proto/terminal_pb2_grpc.py | 101 +++++++ mt5_grpc_proto/mt5_grpc_proto/trade_pb2.py | 46 +++ .../mt5_grpc_proto/trade_pb2_grpc.py | 101 +++++++ mt5_grpc_proto/pyproject.toml | 3 + mt5_grpc_proto/requirements.txt | 3 + mt5_grpc_proto/setup.py | 38 +++ mt5_grpc_server/Readme.md | 56 ++++ mt5_grpc_server/mt5_grpc_server/__init__.py | 1 + .../mt5_grpc_server/grpc_server.py | 89 ++++++ .../mt5_grpc_server/imp/__init__.py | 16 + .../mt5_grpc_server/imp/account_service.py | 82 ++++++ .../mt5_grpc_server/imp/deals_history.py | 120 ++++++++ .../mt5_grpc_server/imp/history_orders.py | 161 ++++++++++ .../mt5_grpc_server/imp/initialize.py | 59 ++++ .../mt5_grpc_server/imp/market_book.py | 64 ++++ .../mt5_grpc_server/imp/market_data.py | 159 ++++++++++ .../mt5_grpc_server/imp/metatrader.py | 61 ++++ mt5_grpc_server/mt5_grpc_server/imp/order.py | 193 ++++++++++++ .../mt5_grpc_server/imp/order_calc.py | 57 ++++ .../mt5_grpc_server/imp/order_check.py | 38 +++ .../mt5_grpc_server/imp/positions.py | 183 ++++++++++++ .../mt5_grpc_server/imp/symbol_info.py | 164 +++++++++++ .../mt5_grpc_server/imp/symbol_info_tick.py | 61 ++++ .../mt5_grpc_server/imp/symbols.py | 57 ++++ .../mt5_grpc_server/imp/terminal_info.py | 42 +++ mt5_grpc_server/mt5_grpc_server/imp/trade.py | 92 ++++++ mt5_grpc_server/pyproject.toml | 3 + mt5_grpc_server/requirements.txt | 5 + mt5_grpc_server/setup.py | 57 ++++ protos/account.proto | 120 ++++---- protos/common.proto | 34 +++ protos/current_tick.proto | 90 ------ protos/deal.proto | 122 ++------ protos/history_orders.proto | 69 +++++ protos/initialize.proto | 62 ++++ protos/market_book.proto | 66 +++++ protos/market_data.proto | 163 +++++++++++ protos/order.proto | 142 +++------ protos/order_calc.proto | 43 +++ protos/order_check.proto | 36 +++ protos/position.proto | 78 +++-- protos/symbol_info.proto | 132 +++++++++ protos/symbol_info_tick.proto | 50 ++++ protos/symbols.proto | 62 ++++ protos/terminal.proto | 86 ++++++ protos/trade.proto | 206 ++++++------- requirements.txt | 5 + start_server_under_wine.sh | 7 +- 120 files changed, 8997 insertions(+), 508 deletions(-) create mode 100644 .idea/deployment.xml create mode 100644 .idea/sshConfigs.xml create mode 100644 .idea/webServers.xml create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 client_example.py create mode 100644 docs/mt5_reference/account_info.md create mode 100644 docs/mt5_reference/copy_rates_from.md create mode 100644 docs/mt5_reference/copy_rates_from_pos.md create mode 100644 docs/mt5_reference/copy_rates_range.md create mode 100644 docs/mt5_reference/copy_ticks_from.md create mode 100644 docs/mt5_reference/copy_ticks_range.md create mode 100644 docs/mt5_reference/history_deals_get.md create mode 100644 docs/mt5_reference/history_orders_get.md create mode 100644 docs/mt5_reference/history_orders_total.md create mode 100644 docs/mt5_reference/initialize.md create mode 100644 docs/mt5_reference/last_error.md create mode 100644 docs/mt5_reference/login.md create mode 100644 docs/mt5_reference/market_book_add.md create mode 100644 docs/mt5_reference/market_book_get.md create mode 100644 docs/mt5_reference/market_book_release.md create mode 100644 docs/mt5_reference/order_calc_margin.md create mode 100644 docs/mt5_reference/order_calc_profit.md create mode 100644 docs/mt5_reference/order_check.md create mode 100644 docs/mt5_reference/order_send.md create mode 100644 docs/mt5_reference/orders_get.md create mode 100644 docs/mt5_reference/orders_total.md create mode 100644 docs/mt5_reference/positions_get.md create mode 100644 docs/mt5_reference/shutdown.md create mode 100644 docs/mt5_reference/symbol_info.md create mode 100644 docs/mt5_reference/symbol_info_tick.md create mode 100644 docs/mt5_reference/symbol_select.md create mode 100644 docs/mt5_reference/symbols_get.md create mode 100644 docs/mt5_reference/symbols_total.md create mode 100644 docs/mt5_reference/terminal_info.md create mode 100644 docs/mt5_reference/version.md delete mode 100644 generated/__init__.py delete mode 100644 imp/__init__.py create mode 100644 mt5_grpc_proto/MANIFEST.in create mode 100644 mt5_grpc_proto/Readme.md create mode 100644 mt5_grpc_proto/mt5_grpc_proto/__init__.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/account_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/account_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/common_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/common_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/deal_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/deal_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/history_orders_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/history_orders_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/initialize_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/initialize_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/market_book_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/market_book_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/market_data_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/market_data_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/order_calc_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/order_calc_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/order_check_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/order_check_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/order_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/order_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/position_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/position_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/symbol_info_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/symbol_info_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/symbol_info_tick_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/symbol_info_tick_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/symbols_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/symbols_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/terminal_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/terminal_pb2_grpc.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/trade_pb2.py create mode 100644 mt5_grpc_proto/mt5_grpc_proto/trade_pb2_grpc.py create mode 100644 mt5_grpc_proto/pyproject.toml create mode 100644 mt5_grpc_proto/requirements.txt create mode 100644 mt5_grpc_proto/setup.py create mode 100644 mt5_grpc_server/Readme.md create mode 100644 mt5_grpc_server/mt5_grpc_server/__init__.py create mode 100644 mt5_grpc_server/mt5_grpc_server/grpc_server.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/__init__.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/account_service.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/deals_history.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/history_orders.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/initialize.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/market_book.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/market_data.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/metatrader.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/order.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/order_calc.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/order_check.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/positions.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/symbol_info.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/symbol_info_tick.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/symbols.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/terminal_info.py create mode 100644 mt5_grpc_server/mt5_grpc_server/imp/trade.py create mode 100644 mt5_grpc_server/pyproject.toml create mode 100644 mt5_grpc_server/requirements.txt create mode 100644 mt5_grpc_server/setup.py create mode 100644 protos/common.proto delete mode 100644 protos/current_tick.proto create mode 100644 protos/history_orders.proto create mode 100644 protos/initialize.proto create mode 100644 protos/market_book.proto create mode 100644 protos/market_data.proto create mode 100644 protos/order_calc.proto create mode 100644 protos/order_check.proto create mode 100644 protos/symbol_info.proto create mode 100644 protos/symbol_info_tick.proto create mode 100644 protos/symbols.proto create mode 100644 protos/terminal.proto create mode 100644 requirements.txt diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..1b99967 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file diff --git a/.idea/sshConfigs.xml b/.idea/sshConfigs.xml new file mode 100644 index 0000000..33e2460 --- /dev/null +++ b/.idea/sshConfigs.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/webServers.xml b/.idea/webServers.xml new file mode 100644 index 0000000..b182d69 --- /dev/null +++ b/.idea/webServers.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..95280a3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.0] - 2024-12-25 + +### Added +- Initial release of MT5 gRPC Server +- Basic MetaTrader 5 operations support through gRPC +- Protocol buffer definitions for MT5 operations +- Example client implementation +- Basic documentation +- Windows support under Wine for Linux/macOS users + +### Dependencies +- Python >=3.8 +- gRPC framework +- MetaTrader 5 terminal +- Required Python packages listed in requirements.txt \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..07a0eaa --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 MT5-RPC-server + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5850e36 --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# Metatrader5 RPC Server 🚀 + +## 📋 Project Description +This project is a gRPC server for interacting with Metatrader 5, designed specifically to provide a convenient way to host an API service on Windows and interact with it using any programming language through gRPC. This approach allows you to build trading applications and services in your preferred language while keeping MetaTrader 5 running on Windows. + +## 🏗️ Project Structure + +The project consists of two main packages: + +### 1. MT5 gRPC Proto (`mt5-grpc-proto`) +Protocol Buffers and gRPC service definitions package. Contains the contract between the MT5 gRPC server and its clients. + +Installation: +```bash +pip install mt5-grpc-proto +``` + +### 2. MT5 gRPC Server (`mt5-grpc-server`) +The server implementation that interfaces with MetaTrader 5 terminal. + +Installation: +```bash +pip install mt5-grpc-server +``` + +## ✨ Features +- Account information retrieval +- Trading symbol management +- Sending and checking trading orders +- Market data acquisition +- Position management +- Retrieving trade and order history +- Terminal information retrieval + +## 💡 Key Benefits +- Run MetaTrader 5 on Windows while accessing it from any OS +- Build trading applications in any language that supports gRPC +- High-performance binary protocol communication +- Bi-directional streaming capabilities +- Type-safe API interface + +## 🖥️ Server Usage + +### Basic Start +```bash +mt5-grpc-server +``` +The server will start on default port 50051 and host 0.0.0.0 + +### Secure Connection +```bash +mt5-grpc-server --host 127.0.0.1 --port 50052 --secure --cert-file server.crt --private-key-file server.key +``` + +### Command-line Options +- `--host HOST`: Host address to bind the server to (default: "0.0.0.0") +- `--port PORT`: Port number to listen on (default: 50051) +- `--secure`: Enable secure connection with SSL/TLS +- `--cert-file FILE`: Path to the SSL certificate file (required if --secure is used) +- `--private-key-file FILE`: Path to the private key file (required if --secure is used) + +## 🛠️ Development Setup + +1. Clone the repository: +```bash +git clone https://github.com/your-username/Metatrader5-gRPC-server.git +cd Metatrader5-gRPC-server +``` + +## 🔄 Generating Proto Files +To regenerate proto files during development, use: +```bash +./generate_proto.sh +``` + +## 🐧 Running Under Wine (Linux, MacOS) +If you need to run the server on Linux: +```bash +./start_server_under_wine.sh +``` + +## 📚 Usage Examples +See `client_example.py` for client code examples. You can implement clients in any language that supports gRPC. + +## 📄 License +MIT License + +## 🤝 Contributing +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. \ No newline at end of file diff --git a/client_example.py b/client_example.py new file mode 100644 index 0000000..fc8ca10 --- /dev/null +++ b/client_example.py @@ -0,0 +1,153 @@ +from datetime import datetime, timedelta +import random + +import grpc +from mt5_grpc_proto import common_pb2, common_pb2_grpc, position_pb2, deal_pb2, history_orders_pb2_grpc, position_pb2_grpc, \ + symbol_info_pb2_grpc, history_orders_pb2, terminal_pb2, symbols_pb2_grpc, order_pb2, terminal_pb2_grpc +from mt5_grpc_proto import symbol_info_pb2, deal_pb2_grpc, order_pb2_grpc, symbols_pb2 + +if __name__ == '__main__': + with (grpc.insecure_channel('192.168.10.100:50051') as channel): + # Connect to MetaTrader + mt = common_pb2_grpc.MetaTraderServiceStub(channel) + mt.Connect(common_pb2.Empty()) + + # Get terminal info + terminal = terminal_pb2_grpc.TerminalInfoServiceStub(channel) + terminal_info = terminal.GetTerminalInfo(terminal_pb2.TerminalInfoRequest()) + print("Terminal Info:") + print(terminal_info) + + # Get symbols service stub + symbols = symbols_pb2_grpc.SymbolsServiceStub(channel) + + # Get list of all symbols + symbols_list = symbols.GetSymbols(symbols_pb2.SymbolsGetRequest()) + print("Available symbols:", [symbol for symbol in symbols_list.symbols]) + + # Select random symbol and set it as active + if symbols_list.symbols: + random_symbol = random.choice(symbols_list.symbols) + select_response = symbols.SelectSymbol(symbols_pb2.SymbolSelectRequest( + symbol=random_symbol, + enable=True + )) + if select_response.success: + print(f"Selected random symbol: {random_symbol}") + else: + print(f"Failed to select symbol: {select_response.error.description}") + + positions_total = position_pb2_grpc.PositionsServiceStub(channel).GetPositionsTotal( + position_pb2.PositionsTotalRequest() + ) + + print("Total positions: ", positions_total.total) + + # Get all positions + # Get symbol info for EURUSD + symbol_info = symbol_info_pb2_grpc.SymbolInfoServiceStub(channel).GetSymbolInfo(symbol_info_pb2.SymbolInfoRequest( + symbol="EURUSD" + )) + + if symbol_info.error.code == 0: + info = symbol_info.symbol_info + print("\nEURUSD Symbol Details:") + print(f"Bid: {info.bid}") + print(f"Ask: {info.ask}") + print(f"Point: {info.point}") + print(f"Digits: {info.digits}") + print(f"Spread: {info.spread}") + print(f"Trade mode: {info.trade_mode}") + print(f"Volume min: {info.volume_min}") + print(f"Volume max: {info.volume_max}") + print(f"Volume step: {info.volume_step}") + else: + print(f"Failed to get EURUSD info: {symbol_info.error.message}") + + # Get orders history + orders_service = order_pb2_grpc.OrdersServiceStub(channel) + orders = orders_service.GetOrders(order_pb2.OrdersGetRequest()) + print("\nActive Orders:") + if orders.error.code == 0: + for order in orders.orders: + print(f"Order #{order.ticket}:") + print(f" Symbol: {order.symbol}") + print(f" Type: {order.type}") + print(f" Volume: {order.volume_current}") + print(f" Open Price: {order.price_open}") + print(f" Current Price: {order.price_current}") + print(f" Stop Loss: {order.stop_loss}") + print(f" Take Profit: {order.take_profit}") + print(f" Comment: {order.comment}") + else: + print(f"Failed to get orders: {orders.error.message}") + + # Get deals history for the last day + trade_history = deal_pb2_grpc.TradeHistoryServiceStub(channel) + + # Calculate timestamps for the last 24 hours + now = datetime.now() + yesterday = now - timedelta(days=10) + + deals_request = deal_pb2.DealsRequest( + time_filter=common_pb2.TimeFilter( + date_from=int(yesterday.timestamp()), + date_to=int(now.timestamp()) + ) + ) + + deals = trade_history.GetDeals(deals_request) + print("\nDeals History (last 24 hours):") + if deals.error is None or deals.error.code == 0: + for deal in deals.deals: + print(f"Deal #{deal.ticket}:") + print(f" Symbol: {deal.symbol}") + print(f" Type: {deal.type}") + print(f" Entry: {deal.entry}") + print(f" Volume: {deal.volume}") + print(f" Price: {deal.price}") + print(f" Profit: {deal.profit}") + print(f" Commission: {deal.commission}") + print(f" Swap: {deal.swap}") + print(f" Comment: {deal.comment}") + else: + print(f"Failed to get deals history: {deals.error.message}") + + # Get orders history for the last 10 days + history_orders_service = history_orders_pb2_grpc.HistoryOrdersServiceStub(channel) + + # Get total number of orders in history + history_orders_total = history_orders_service.GetHistoryOrdersTotal( + history_orders_pb2.HistoryOrdersTotalRequest( + date_from=int(yesterday.timestamp()), + date_to=int(now.timestamp()) + ) + ) + print(f"\nTotal orders in history for last 10 days: {history_orders_total.total}") + + # Get detailed orders history + history_orders_request = history_orders_pb2.HistoryOrdersRequest( + time_filter=common_pb2.TimeFilter( + date_from=int(yesterday.timestamp()), + date_to=int(now.timestamp()) + ), + group="*" # Get all symbols + ) + + history_orders = history_orders_service.GetHistoryOrders(history_orders_request) + print("\nOrders History (last 10 days):") + if history_orders.error is None or history_orders.error.code == 0: + for order in history_orders.orders: + print(f"Order #{order.ticket}:") + print(f" Symbol: {order.symbol}") + print(f" Type: {order.type}") + print(f" State: {order.state}") + print(f" Volume Initial: {order.volume_initial}") + print(f" Volume Current: {order.volume_current}") + print(f" Price Open: {order.price_open}") + print(f" Stop Loss: {order.stop_loss}") + print(f" Take Profit: {order.take_profit}") + print(f" Comment: {order.comment}") + else: + print(f"Failed to get orders history: {history_orders.error.message}") + \ No newline at end of file diff --git a/docs/mt5_reference/account_info.md b/docs/mt5_reference/account_info.md new file mode 100644 index 0000000..461ce6d --- /dev/null +++ b/docs/mt5_reference/account_info.md @@ -0,0 +1,96 @@ +# account_info() + +Get info on the current trading account. + +## Syntax + +```python +account_info() +``` + +## Return Value + +Return info in the form of a named tuple structure (namedtuple) containing: + +| Field | Type | Description | +|-------|------|-------------| +| login | int | Account number | +| trade_mode | int | Account trade mode | +| leverage | int | Account leverage | +| limit_orders | int | Maximum allowed number of active pending orders | +| margin_so_mode | int | Mode for setting the minimal allowed margin | +| trade_allowed | bool | Permission to trade for the current account | +| trade_expert | bool | Permission to trade for an Expert Advisor | +| margin_mode | int | Margin calculation mode | +| currency_digits | int | The number of decimal places in the account currency | +| fifo_close | bool | Flag indicating that positions can only be closed by FIFO rule | +| balance | float | Account balance in the deposit currency | +| credit | float | Credit in the deposit currency | +| profit | float | Current profit in the deposit currency | +| equity | float | Account equity in the deposit currency | +| margin | float | Account margin used in the deposit currency | +| margin_free | float | Free margin of account in the deposit currency | +| margin_level | float | Account margin level in percents | +| margin_so_call | float | Margin call level | +| margin_so_so | float | Margin stop out level | +| margin_initial | float | Initial margin | +| margin_maintenance | float | Maintenance margin | +| assets | float | Current assets of account | +| liabilities | float | Current liabilities of account | +| commission_blocked | float | Current blocked commission amount | +| name | str | Client name | +| server | str | Trade server name | +| currency | str | Account currency | +| company | str | Name of a company that serves the account | + +Returns None in case of an error. The error info can be obtained using [last_error()](./last_error.md). + +## Note + +The function returns all data that can be obtained using AccountInfoInteger, AccountInfoDouble and AccountInfoString in one call. + +## Example + +```python +import MetaTrader5 as mt5 +import pandas as pd + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# connect to the trade account specifying a password and a server +authorized=mt5.login(25115284, password="gqz0343lbdm") +if authorized: + account_info=mt5.account_info() + if account_info!=None: + # display trading account data 'as is' + print(account_info) + # display trading account data in the form of a dictionary + print("Show account_info()._asdict():") + account_info_dict = mt5.account_info()._asdict() + for prop in account_info_dict: + print(" {}={}".format(prop, account_info_dict[prop])) + print() + + # convert the dictionary into DataFrame and print + df=pd.DataFrame(list(account_info_dict.items()),columns=['property','value']) + print("account_info() as dataframe:") + print(df) +else: + print("failed to connect to trade account 25115284 with password=gqz0343lbdm, error code =",mt5.last_error()) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [initialize()](./initialize.md) +- [shutdown()](./shutdown.md) +- [login()](./login.md) \ No newline at end of file diff --git a/docs/mt5_reference/copy_rates_from.md b/docs/mt5_reference/copy_rates_from.md new file mode 100644 index 0000000..1ceddb1 --- /dev/null +++ b/docs/mt5_reference/copy_rates_from.md @@ -0,0 +1,117 @@ +# copy_rates_from + +Get bars from the MetaTrader 5 terminal starting from the specified date. + +## Syntax + +```python +copy_rates_from( + symbol, # financial instrument name + timeframe, # timeframe + date_from, # initial bar open date + count # number of bars +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name, for example, "EURUSD". Required unnamed parameter. | +| timeframe | int | Timeframe the bars are requested for. Set by a value from the TIMEFRAME enumeration. Required unnamed parameter. | +| date_from | datetime | Date of opening of the first bar from the requested sample. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter. | +| count | int | Number of bars to receive. Required unnamed parameter. | + +## Return Value + +Returns bars as the numpy array with the named time, open, high, low, close, tick_volume, spread and real_volume columns. + +Returns None in case of an error. The info on the error can be obtained using [last_error()](./last_error.md). + +## Note + +The function is similar to CopyRates in MQL5. + +Only data whose date is less than (earlier) or equal to the date specified will be returned. It means, the open time of any bar is always less or equal to the specified one. + +MetaTrader 5 terminal provides bars only within a history available to a user on charts. The number of bars available to users is set in the "Max. bars in chart" parameter. + +When creating the 'datetime' object, Python uses the local time zone, while MetaTrader 5 stores tick and bar open time in UTC time zone (without the shift). Therefore, 'datetime' should be created in UTC time for executing functions that use time. Data received from the MetaTrader 5 terminal has UTC time. + +## TIMEFRAME Enumeration + +| ID | Description | +|----|-------------| +| TIMEFRAME_M1 | 1 minute | +| TIMEFRAME_M2 | 2 minutes | +| TIMEFRAME_M3 | 3 minutes | +| TIMEFRAME_M4 | 4 minutes | +| TIMEFRAME_M5 | 5 minutes | +| TIMEFRAME_M6 | 6 minutes | +| TIMEFRAME_M10 | 10 minutes | +| TIMEFRAME_M12 | 12 minutes | +| TIMEFRAME_M15 | 15 minutes | +| TIMEFRAME_M20 | 20 minutes | +| TIMEFRAME_M30 | 30 minutes | +| TIMEFRAME_H1 | 1 hour | +| TIMEFRAME_H2 | 2 hours | +| TIMEFRAME_H3 | 3 hours | +| TIMEFRAME_H4 | 4 hours | +| TIMEFRAME_H6 | 6 hours | +| TIMEFRAME_H8 | 8 hours | +| TIMEFRAME_H12 | 12 hours | +| TIMEFRAME_D1 | 1 day | +| TIMEFRAME_W1 | 1 week | +| TIMEFRAME_MN1 | 1 month | + +## Example + +```python +from datetime import datetime +import MetaTrader5 as mt5 +import time + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# import the 'pandas' module for displaying data obtained in the tabular form +import pandas as pd +pd.set_option('display.max_columns', 500) # number of columns to be displayed +pd.set_option('display.width', 1500) # max table width to display +# import pytz module for working with time zone +import pytz + +# establish connection to MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# set time zone to UTC +timezone = pytz.timezone("Etc/UTC") +# create 'datetime' object in UTC time zone to avoid the implementation of a local time zone offset +utc_from = datetime(2020, 1, 10, tzinfo=timezone) +# get 10 EURUSD H4 bars starting from 01.10.2020 in UTC time zone +rates = mt5.copy_rates_from("EURUSD", mt5.TIMEFRAME_H4, utc_from, 10) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() + +# display each element of obtained data in a new line +print("Display obtained data 'as is'") +for rate in rates: + print(rate) + +# create DataFrame out of the obtained data +rates_frame = pd.DataFrame(rates) +# convert time in seconds into the datetime format +rates_frame['time']=pd.to_datetime(rates_frame['time'], unit='s') + +# display data +print("\nDisplay dataframe with data") +print(rates_frame) +``` + +## See also + +[CopyRates](./copyrates.md), [copy_rates_from_pos](./copy_rates_from_pos.md), [copy_rates_range](./copy_rates_range.md), [copy_ticks_from](./copy_ticks_from.md), [copy_ticks_range](./copy_ticks_range.md) \ No newline at end of file diff --git a/docs/mt5_reference/copy_rates_from_pos.md b/docs/mt5_reference/copy_rates_from_pos.md new file mode 100644 index 0000000..14c9aae --- /dev/null +++ b/docs/mt5_reference/copy_rates_from_pos.md @@ -0,0 +1,81 @@ +# copy_rates_from_pos + +Get bars from the MetaTrader 5 terminal starting from the specified index. + +## Syntax + +```python +copy_rates_from_pos( + symbol, # financial instrument name + timeframe, # timeframe + start_pos, # initial bar index + count # number of bars +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name, for example, "EURUSD". Required unnamed parameter. | +| timeframe | int | Timeframe the bars are requested for. Set by a value from the TIMEFRAME enumeration. Required unnamed parameter. | +| start_pos | int | Initial index of the bar the data are requested from. The numbering of bars goes from present to past. Thus, the zero bar means the current one. Required unnamed parameter. | +| count | int | Number of bars to receive. Required unnamed parameter. | + +## Return Value + +Returns bars as the numpy array with the named time, open, high, low, close, tick_volume, spread and real_volume columns. + +Returns None in case of an error. The info on the error can be obtained using [last_error()](./last_error.md). + +## Note + +The function is similar to CopyRates in MQL5. + +MetaTrader 5 terminal provides bars only within a history available to a user on charts. The number of bars available to users is set in the "Max. bars in chart" parameter. + +## Example + +```python +from datetime import datetime +import MetaTrader5 as mt5 +import time + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# import the 'pandas' module for displaying data obtained in the tabular form +import pandas as pd +pd.set_option('display.max_columns', 500) # number of columns to be displayed +pd.set_option('display.width', 1500) # max table width to display + +# establish connection to MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# get 10 GBPUSD D1 bars from the current day +rates = mt5.copy_rates_from_pos("GBPUSD", mt5.TIMEFRAME_D1, 0, 10) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() + +# display each element of obtained data in a new line +print("Display obtained data 'as is'") +for rate in rates: + print(rate) + +# create DataFrame out of the obtained data +rates_frame = pd.DataFrame(rates) +# convert time in seconds into the datetime format +rates_frame['time']=pd.to_datetime(rates_frame['time'], unit='s') + +# display data +print("\nDisplay dataframe with data") +print(rates_frame) +``` + +## See also + +[CopyRates](./copyrates.md), [copy_rates_from](./copy_rates_from.md), [copy_rates_range](./copy_rates_range.md), [copy_ticks_from](./copy_ticks_from.md), [copy_ticks_range](./copy_ticks_range.md) \ No newline at end of file diff --git a/docs/mt5_reference/copy_rates_range.md b/docs/mt5_reference/copy_rates_range.md new file mode 100644 index 0000000..b1c5a48 --- /dev/null +++ b/docs/mt5_reference/copy_rates_range.md @@ -0,0 +1,94 @@ +# copy_rates_range + +Get bars in the specified date range from the MetaTrader 5 terminal. + +## Syntax + +```python +copy_rates_range( + symbol, # financial instrument name + timeframe, # timeframe + date_from, # date the bars are requested from + date_to # date, up to which the bars are requested +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name, for example, "EURUSD". Required unnamed parameter. | +| timeframe | int | Timeframe the bars are requested for. Set by a value from the TIMEFRAME enumeration. Required unnamed parameter. | +| date_from | datetime | Date the bars are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Bars with the open time >= date_from are returned. Required unnamed parameter. | +| date_to | datetime | Date, up to which the bars are requested. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Bars with the open time <= date_to are returned. Required unnamed parameter. | + +## Return Value + +Returns bars as the numpy array with the named time, open, high, low, close, tick_volume, spread and real_volume columns. + +Returns None in case of an error. The info on the error can be obtained using [last_error()](./last_error.md). + +## Note + +The function is similar to CopyRates in MQL5. + +MetaTrader 5 terminal provides bars only within a history available to a user on charts. The number of bars available to users is set in the "Max. bars in chart" parameter. + +When creating the 'datetime' object, Python uses the local time zone, while MetaTrader 5 stores tick and bar open time in UTC time zone (without the shift). Therefore, 'datetime' should be created in UTC time for executing functions that use time. Data received from the MetaTrader 5 terminal has UTC time. + +## Example + +```python +from datetime import datetime +import MetaTrader5 as mt5 +import time + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# import the 'pandas' module for displaying data obtained in the tabular form +import pandas as pd +pd.set_option('display.max_columns', 500) # number of columns to be displayed +pd.set_option('display.width', 1500) # max table width to display + +# import pytz module for working with time zone +import pytz + +# establish connection to MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# set time zone to UTC +timezone = pytz.timezone("Etc/UTC") +# create 'datetime' objects in UTC time zone to avoid the implementation of a local time zone offset +utc_from = datetime(2020, 1, 10, tzinfo=timezone) +utc_to = datetime(2020, 1, 11, hour = 13, tzinfo=timezone) +# get bars from USDJPY M5 within the interval of 2020.01.10 00:00 - 2020.01.11 13:00 in UTC time zone +rates = mt5.copy_rates_range("USDJPY", mt5.TIMEFRAME_M5, utc_from, utc_to) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() + +# display each element of obtained data in a new line +print("Display obtained data 'as is'") +counter=0 +for rate in rates: + counter+=1 + if counter<=10: + print(rate) + +# create DataFrame out of the obtained data +rates_frame = pd.DataFrame(rates) +# convert time in seconds into the datetime format +rates_frame['time']=pd.to_datetime(rates_frame['time'], unit='s') + +# display data +print("\nDisplay dataframe with data") +print(rates_frame.head(10)) +``` + +## See also + +[CopyRates](./copyrates.md), [copy_rates_from](./copy_rates_from.md), [copy_rates_from_pos](./copy_rates_from_pos.md), [copy_ticks_from](./copy_ticks_from.md), [copy_ticks_range](./copy_ticks_range.md) \ No newline at end of file diff --git a/docs/mt5_reference/copy_ticks_from.md b/docs/mt5_reference/copy_ticks_from.md new file mode 100644 index 0000000..f14d8ab --- /dev/null +++ b/docs/mt5_reference/copy_ticks_from.md @@ -0,0 +1,112 @@ +# copy_ticks_from + +Get ticks from the MetaTrader 5 terminal starting from the specified date. + +## Syntax + +```python +copy_ticks_from( + symbol, # symbol name + date_from, # date the ticks are requested from + count, # number of requested ticks + flags # combination of flags defining the type of requested ticks +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name, for example, "EURUSD". Required unnamed parameter. | +| date_from | datetime | Date the ticks are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter. | +| count | int | Number of ticks to receive. Required unnamed parameter. | +| flags | int | A flag to define the type of the requested ticks. COPY_TICKS_INFO – ticks with Bid and/or Ask changes, COPY_TICKS_TRADE – ticks with changes in Last and Volume, COPY_TICKS_ALL – all ticks. Required unnamed parameter. | + +## Return Value + +Returns ticks as the numpy array with the named time, bid, ask, last and flags columns. The 'flags' value can be a combination of flags from the TICK_FLAG enumeration. + +Returns None in case of an error. The info on the error can be obtained using [last_error()](./last_error.md). + +## Note + +The function is similar to CopyTicks in MQL5. + +When creating the 'datetime' object, Python uses the local time zone, while MetaTrader 5 stores tick and bar open time in UTC time zone (without the shift). Therefore, 'datetime' should be created in UTC time for executing functions that use time. Data received from the MetaTrader 5 terminal has UTC time. + +### COPY_TICKS enumeration + +| ID | Description | +|----|-------------| +| COPY_TICKS_ALL | all ticks | +| COPY_TICKS_INFO | ticks containing Bid and/or Ask price changes | +| COPY_TICKS_TRADE | ticks containing Last and/or Volume price changes | + +### TICK_FLAG enumeration + +| ID | Description | +|----|-------------| +| TICK_FLAG_BID | Bid price changed | +| TICK_FLAG_ASK | Ask price changed | +| TICK_FLAG_LAST | Last price changed | +| TICK_FLAG_VOLUME | Volume changed | +| TICK_FLAG_BUY | last Buy price changed | +| TICK_FLAG_SELL | last Sell price changed | + +## Example + +```python +from datetime import datetime +import MetaTrader5 as mt5 +import time + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# import the 'pandas' module for displaying data obtained in the tabular form +import pandas as pd +pd.set_option('display.max_columns', 500) # number of columns to be displayed +pd.set_option('display.width', 1500) # max table width to display + +# import pytz module for working with time zone +import pytz + +# establish connection to MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# set time zone to UTC +timezone = pytz.timezone("Etc/UTC") +# create 'datetime' object in UTC time zone to avoid the implementation of a local time zone offset +utc_from = datetime(2020, 1, 10, tzinfo=timezone) +# request 100 000 EURUSD ticks starting from 10.01.2019 in UTC time zone +ticks = mt5.copy_ticks_from("EURUSD", utc_from, 100000, mt5.COPY_TICKS_ALL) +print("Ticks received:",len(ticks)) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() + +# display data on each tick on a new line +print("Display obtained ticks 'as is'") +count = 0 +for tick in ticks: + count+=1 + print(tick) + if count >= 10: + break + +# create DataFrame out of the obtained data +ticks_frame = pd.DataFrame(ticks) +# convert time in seconds into the datetime format +ticks_frame['time']=pd.to_datetime(ticks_frame['time'], unit='s') + +# display data +print("\nDisplay dataframe with ticks") +print(ticks_frame.head(10)) +``` + +## See also + +[CopyRates](./copyrates.md), [copy_rates_from_pos](./copy_rates_from_pos.md), [copy_rates_range](./copy_rates_range.md), [copy_ticks_from](./copy_ticks_from.md), [copy_ticks_range](./copy_ticks_range.md) \ No newline at end of file diff --git a/docs/mt5_reference/copy_ticks_range.md b/docs/mt5_reference/copy_ticks_range.md new file mode 100644 index 0000000..af061dc --- /dev/null +++ b/docs/mt5_reference/copy_ticks_range.md @@ -0,0 +1,111 @@ +# copy_ticks_range + +Get ticks for the specified date range from the MetaTrader 5 terminal. + +## Syntax + +```python +copy_ticks_range( + symbol, # symbol name + date_from, # date the ticks are requested from + date_to, # date, up to which the ticks are requested + flags # combination of flags defining the type of requested ticks +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name, for example, "EURUSD". Required unnamed parameter. | +| date_from | datetime | Date the ticks are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter. | +| date_to | datetime | Date, up to which the ticks are requested. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter. | +| flags | int | A flag to define the type of the requested ticks. COPY_TICKS_INFO – ticks with Bid and/or Ask changes, COPY_TICKS_TRADE – ticks with changes in Last and Volume, COPY_TICKS_ALL – all ticks. Required unnamed parameter. | + +## Return Value + +Returns ticks as the numpy array with the named time, bid, ask, last and flags columns. The 'flags' value can be a combination of flags from the TICK_FLAG enumeration. + +Returns None in case of an error. The info on the error can be obtained using [last_error()](./last_error.md). + +## Note + +When creating the 'datetime' object, Python uses the local time zone, while MetaTrader 5 stores tick and bar open time in UTC time zone (without the shift). Therefore, 'datetime' should be created in UTC time for executing functions that use time. The data obtained from MetaTrader 5 have UTC time. + +### COPY_TICKS enumeration + +| ID | Description | +|----|-------------| +| COPY_TICKS_ALL | all ticks | +| COPY_TICKS_INFO | ticks containing Bid and/or Ask price changes | +| COPY_TICKS_TRADE | ticks containing Last and/or Volume price changes | + +### TICK_FLAG enumeration + +| ID | Description | +|----|-------------| +| TICK_FLAG_BID | Bid price changed | +| TICK_FLAG_ASK | Ask price changed | +| TICK_FLAG_LAST | Last price changed | +| TICK_FLAG_VOLUME | Volume changed | +| TICK_FLAG_BUY | last Buy price changed | +| TICK_FLAG_SELL | last Sell price changed | + +## Example + +```python +from datetime import datetime +import MetaTrader5 as mt5 +import time + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# import the 'pandas' module for displaying data obtained in the tabular form +import pandas as pd +pd.set_option('display.max_columns', 500) # number of columns to be displayed +pd.set_option('display.width', 1500) # max table width to display + +# import pytz module for working with time zone +import pytz + +# establish connection to MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# set time zone to UTC +timezone = pytz.timezone("Etc/UTC") +# create 'datetime' objects in UTC time zone to avoid the implementation of a local time zone offset +utc_from = datetime(2020, 1, 10, tzinfo=timezone) +utc_to = datetime(2020, 1, 11, tzinfo=timezone) +# request AUDUSD ticks within 11.01.2020 - 11.01.2020 +ticks = mt5.copy_ticks_range("AUDUSD", utc_from, utc_to, mt5.COPY_TICKS_ALL) +print("Ticks received:",len(ticks)) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() + +# display data on each tick on a new line +print("Display obtained ticks 'as is'") +count = 0 +for tick in ticks: + count+=1 + print(tick) + if count >= 10: + break + +# create DataFrame out of the obtained data +ticks_frame = pd.DataFrame(ticks) +# convert time in seconds into the datetime format +ticks_frame['time']=pd.to_datetime(ticks_frame['time'], unit='s') + +# display data +print("\nDisplay dataframe with ticks") +print(ticks_frame.head(10)) +``` + +## See also + +[CopyRates](./copyrates.md), [copy_rates_from_pos](./copy_rates_from_pos.md), [copy_rates_range](./copy_rates_range.md), [copy_ticks_from](./copy_ticks_from.md), [copy_ticks_range](./copy_ticks_range.md) \ No newline at end of file diff --git a/docs/mt5_reference/history_deals_get.md b/docs/mt5_reference/history_deals_get.md new file mode 100644 index 0000000..db15608 --- /dev/null +++ b/docs/mt5_reference/history_deals_get.md @@ -0,0 +1,122 @@ +# history_deals_get() + +Get deals from trading history within the specified interval with the ability to filter by ticket or position. + +## Syntax + +1. Call specifying a time interval: +```python +history_deals_get( + date_from, # date the deals are requested from + date_to, # date, up to which the deals are requested + group="GROUP" # filter for selecting deals for symbols +) +``` + +2. Call specifying the order ticket: +```python +history_deals_get( + ticket=TICKET # order ticket +) +``` + +3. Call specifying the position ticket: +```python +history_deals_get( + position=POSITION # position ticket +) +``` + +## Parameters + +- `date_from` [in] - Date the orders are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter is specified first. +- `date_to` [in] - Date, up to which the orders are requested. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter is specified second. +- `group` [in] - The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only deals meeting a specified criteria for a symbol name. +- `ticket` [in] - Ticket of an order (stored in DEAL_ORDER) all deals should be received for. Optional parameter. If not specified, the filter is not applied. +- `position` [in] - Ticket of a position (stored in DEAL_POSITION_ID) all deals should be received for. Optional parameter. If not specified, the filter is not applied. + +### Group Filter Format + +The `group` parameter may contain several comma-separated conditions: +- Use '*' as a mask in a condition +- Use '!' for logical negation +- Conditions are applied sequentially +- Include conditions should be specified first, followed by exclusion conditions + +Example: `group="*, !EUR"` means select deals for all symbols first, then exclude ones containing "EUR" in symbol names. + +## Return Value + +Returns info in the form of a named tuple structure (namedtuple) containing: +- ticket: Deal ticket +- order: Order ticket +- time: Deal execution time +- time_msc: Deal execution time in milliseconds +- type: Deal type +- entry: Deal entry - entry in, entry out, reverse +- magic: Expert Advisor ID +- position_id: Position identifier +- reason: Deal execution reason +- volume: Deal volume +- price: Deal price +- commission: Deal commission +- swap: Cumulative swap +- profit: Deal profit +- fee: Deal fee charged +- symbol: Deal symbol +- comment: Deal comment +- external_id: Deal identifier in an external trading system + +Returns None in case of error. The error info can be obtained using [last_error()](./last_error.md). + +## Note + +The function allows receiving all history deals within a specified period in a single call similar to the HistoryDealsTotal and HistoryDealSelect tandem in MQL5. + +## Example + +```python +import MetaTrader5 as mt5 +import pandas as pd +pd.set_option('display.max_columns', 500) # number of columns to be displayed +pd.set_option('display.width', 1500) # max table width to display + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# get deals for symbols whose names contain "GBP" within a specified interval +from_date = datetime(2020, 1, 1) +to_date = datetime.now() +deals = mt5.history_deals_get(from_date, to_date, group="*GBP*") +if deals is None: + print("No deals with group=\"*GBP*\", error code={}".format(mt5.last_error())) +elif len(deals) > 0: + print("history_deals_get({}, {}, group=\"*GBP*\")={}".format(from_date, to_date, len(deals))) + # display these deals as a table using pandas.DataFrame + df = pd.DataFrame(list(deals), columns=deals[0]._asdict().keys()) + df['time'] = pd.to_datetime(df['time'], unit='s') + print(df) + +# get all deals related to the position #530218319 +position_id = 530218319 +position_deals = mt5.history_deals_get(position=position_id) +if position_deals is None: + print("No deals with position #{}".format(position_id)) + print("error code =", mt5.last_error()) +elif len(position_deals) > 0: + print("Deals with position id #{}: {}".format(position_id, len(position_deals))) + # display these deals as a table using pandas.DataFrame + df = pd.DataFrame(list(position_deals), columns=position_deals[0]._asdict().keys()) + df['time'] = pd.to_datetime(df['time'], unit='s') + print(df) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [history_deals_total()](./history_deals_total.md) +- [history_orders_get()](./history_orders_get.md) \ No newline at end of file diff --git a/docs/mt5_reference/history_orders_get.md b/docs/mt5_reference/history_orders_get.md new file mode 100644 index 0000000..82ac3c7 --- /dev/null +++ b/docs/mt5_reference/history_orders_get.md @@ -0,0 +1,105 @@ +# history_orders_get() + +Get orders from trading history with the ability to filter by ticket or position. + +## Syntax + +1. Call specifying a time interval: +```python +history_orders_get( + date_from, # date the orders are requested from + date_to, # date, up to which the orders are requested + group="GROUP" # filter for selecting orders by symbols +) +``` + +2. Call specifying the order ticket: +```python +history_orders_get( + ticket=TICKET # order ticket +) +``` + +3. Call specifying the position ticket: +```python +history_orders_get( + position=POSITION # position ticket +) +``` + +## Parameters + +- `date_from` [in] - Date the orders are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter is specified first. +- `date_to` [in] - Date, up to which the orders are requested. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter is specified second. +- `group` [in] - The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only orders meeting a specified criteria for a symbol name. +- `ticket` [in] - Order ticket that should be received. Optional parameter. If not specified, the filter is not applied. +- `position` [in] - Ticket of a position (stored in ORDER_POSITION_ID) all orders should be received for. Optional parameter. If not specified, the filter is not applied. + +### Group Filter Format + +The `group` parameter may contain several comma-separated conditions: +- Use '*' as a mask in a condition +- Use '!' for logical negation +- Conditions are applied sequentially +- Include conditions should be specified first, followed by exclusion conditions + +Example: `group="*, !EUR"` means select orders for all symbols first, then exclude ones containing "EUR" in symbol names. + +## Return Value + +Returns info in the form of a named tuple structure (namedtuple) containing order properties. Returns None in case of error. The error info can be obtained using [last_error()](./last_error.md). + +## Note + +The function allows receiving all history orders within a specified period in a single call similar to the HistoryOrdersTotal and HistoryOrderSelect tandem in MQL5. + +## Example + +```python +from datetime import datetime +import MetaTrader5 as mt5 +import pandas as pd +pd.set_option('display.max_columns', 500) # number of columns to be displayed +pd.set_option('display.width', 1500) # max table width to display + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# get orders for symbols whose names contain "GBP" within a specified interval +from_date = datetime(2020, 1, 1) +to_date = datetime.now() +history_orders = mt5.history_orders_get(from_date, to_date, group="*GBP*") +if history_orders is None: + print("No history orders with group=\"*GBP*\", error code={}".format(mt5.last_error())) +elif len(history_orders) > 0: + print("history_orders_get({}, {}, group=\"*GBP*\")={}".format(from_date, to_date, len(history_orders))) + # display these orders as a table using pandas.DataFrame + df = pd.DataFrame(list(history_orders), columns=history_orders[0]._asdict().keys()) + df['time_setup'] = pd.to_datetime(df['time_setup'], unit='s') + df['time_done'] = pd.to_datetime(df['time_done'], unit='s') + print(df) + +# get all orders related to the position #530218319 +position_id = 530218319 +position_history_orders = mt5.history_orders_get(position=position_id) +if position_history_orders is None: + print("No orders with position #{}".format(position_id)) + print("error code =", mt5.last_error()) +elif len(position_history_orders) > 0: + print("Total history orders on position #{}: {}".format(position_id, len(position_history_orders))) + # display these orders as a table using pandas.DataFrame + df = pd.DataFrame(list(position_history_orders), columns=position_history_orders[0]._asdict().keys()) + df['time_setup'] = pd.to_datetime(df['time_setup'], unit='s') + df['time_done'] = pd.to_datetime(df['time_done'], unit='s') + print(df) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [history_orders_total()](./history_orders_total.md) +- [history_deals_get()](./history_deals_get.md) \ No newline at end of file diff --git a/docs/mt5_reference/history_orders_total.md b/docs/mt5_reference/history_orders_total.md new file mode 100644 index 0000000..a8a60d3 --- /dev/null +++ b/docs/mt5_reference/history_orders_total.md @@ -0,0 +1,53 @@ +# history_orders_total() + +Get the number of orders in trading history within the specified interval. + +## Syntax + +```python +history_orders_total( + date_from, # date the orders are requested from + date_to # date, up to which the orders are requested +) +``` + +## Parameters + +- `date_from` [in] - Date the orders are requested from. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter. +- `date_to` [in] - Date, up to which the orders are requested. Set by the 'datetime' object or as a number of seconds elapsed since 1970.01.01. Required unnamed parameter. + +## Return Value + +Returns an integer value representing the total number of orders in the specified period. + +## Note + +The function is similar to HistoryOrdersTotal in MQL5. + +## Example + +```python +from datetime import datetime +import MetaTrader5 as mt5 + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# get the number of orders in history +from_date = datetime(2020, 1, 1) +to_date = datetime.now() +history_orders = mt5.history_orders_total(from_date, to_date) +if history_orders > 0: + print("Total history orders =", history_orders) +else: + print("Orders not found in history") + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [history_orders_get()](./history_orders_get.md) \ No newline at end of file diff --git a/docs/mt5_reference/initialize.md b/docs/mt5_reference/initialize.md new file mode 100644 index 0000000..84eac0f --- /dev/null +++ b/docs/mt5_reference/initialize.md @@ -0,0 +1,82 @@ +# initialize() + +Establishes a connection with the MetaTrader 5 terminal. + +## Syntax + +There are three ways to call this function: + +1. Without parameters (auto-detect terminal): +```python +initialize() +``` + +2. With path to terminal: +```python +initialize( + path # path to the MetaTrader 5 terminal EXE file +) +``` + +3. With full connection parameters: +```python +initialize( + path, # path to the MetaTrader 5 terminal EXE file + login=LOGIN, # account number + password="PASSWORD", # password + server="SERVER", # server name as specified in the terminal + timeout=TIMEOUT, # timeout in milliseconds + portable=False # portable mode flag +) +``` + +## Parameters + +- `path` [in] - Path to the metatrader.exe or metatrader64.exe file. Optional unnamed parameter. If not specified, the module attempts to find the executable file automatically. + +- `login` [in] - Trading account number. Optional named parameter. If not specified, the last trading account is used. + +- `password` [in] - Trading account password. Optional named parameter. If not specified, the password for the specified trading account saved in the terminal database is applied automatically. + +- `server` [in] - Trade server name. Optional named parameter. If not specified, the server for the specified trading account saved in the terminal database is applied automatically. + +- `timeout` [in] - Connection timeout in milliseconds. Optional named parameter. Default value is 60000 (60 seconds). + +- `portable` [in] - Flag for launching the terminal in portable mode. Optional named parameter. Default value is False. + +## Return Value + +Returns True if the connection to the MetaTrader 5 terminal was established successfully, otherwise returns False. + +## Notes + +- If required, the MetaTrader 5 terminal is launched automatically when executing initialize(). +- The terminal will be launched in portable mode if the portable parameter is set to True. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(login=25115284, server="MetaQuotes-Demo", password="4zatlbqx"): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# display connection status and MetaTrader 5 version +print(mt5.terminal_info()) +print(mt5.version()) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [shutdown()](./shutdown.md) +- [terminal_info()](./terminal_info.md) +- [version()](./version.md) \ No newline at end of file diff --git a/docs/mt5_reference/last_error.md b/docs/mt5_reference/last_error.md new file mode 100644 index 0000000..d23801b --- /dev/null +++ b/docs/mt5_reference/last_error.md @@ -0,0 +1,62 @@ +# last_error() + +Returns data about the last error that occurred during the execution of MetaTrader 5 library functions. + +## Syntax + +```python +last_error() +``` + +## Parameters + +None + +## Return Value + +Returns a tuple containing: +- Error code (integer) +- Error description (string) + +## Error Codes + +| Constant | Value | Description | +|----------|--------|-------------| +| RES_S_OK | 1 | Generic success | +| RES_E_FAIL | -1 | Generic fail | +| RES_E_INVALID_PARAMS | -2 | Invalid arguments/parameters | +| RES_E_NO_MEMORY | -3 | No memory condition | +| RES_E_NOT_FOUND | -4 | No history | +| RES_E_INVALID_VERSION | -5 | Invalid version | +| RES_E_AUTH_FAILED | -6 | Authorization failed | +| RES_E_UNSUPPORTED | -7 | Unsupported method | +| RES_E_AUTO_TRADING_DISABLED | -8 | Auto-trading disabled | +| RES_E_INTERNAL_FAIL | -10000 | Internal IPC general error | +| RES_E_INTERNAL_FAIL_SEND | -10001 | Internal IPC send failed | +| RES_E_INTERNAL_FAIL_RECEIVE | -10002 | Internal IPC recv failed | +| RES_E_INTERNAL_FAIL_INIT | -10003 | Internal IPC initialization fail | +| RES_E_INTERNAL_FAIL_CONNECT | -10003 | Internal IPC no ipc | +| RES_E_INTERNAL_FAIL_TIMEOUT | -10005 | Internal timeout | + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code = ", mt5.last_error()) + quit() + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [version()](./version.md) +- [initialize()](./initialize.md) \ No newline at end of file diff --git a/docs/mt5_reference/login.md b/docs/mt5_reference/login.md new file mode 100644 index 0000000..c5a35d3 --- /dev/null +++ b/docs/mt5_reference/login.md @@ -0,0 +1,74 @@ +# login() + +Connects to a trading account using specified parameters. + +## Syntax + +```python +login( + login, # account number + password="PASSWORD", # password + server="SERVER", # server name as specified in the terminal + timeout=TIMEOUT # timeout +) +``` + +## Parameters + +- `login` [in] - Trading account number. Required unnamed parameter. + +- `password` [in] - Trading account password. Optional named parameter. If not specified, the password saved in the terminal database is applied automatically. + +- `server` [in] - Trade server name. Optional named parameter. If not specified, the last used server is applied automatically. + +- `timeout` [in] - Connection timeout in milliseconds. Optional named parameter. Default value is 60000 (60 seconds). If the connection is not established within the specified time, the call is forcibly terminated and an exception is generated. + +## Return Value + +Returns True if the connection to the trade account was established successfully, otherwise returns False. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# connect to the trade account without specifying a password and a server +account = 17221085 +authorized = mt5.login(account) # the terminal database password is applied if connection data is set to be remembered +if authorized: + print("connected to account #{}".format(account)) +else: + print("failed to connect at account #{}, error code: {}".format(account, mt5.last_error())) + +# now connect to another trading account specifying the password +account = 25115284 +authorized = mt5.login(account, password="gqrtz0lbdm") +if authorized: + # display trading account data 'as is' + print(mt5.account_info()) + # display trading account data in the form of a list + print("Show account_info()._asdict():") + account_info_dict = mt5.account_info()._asdict() + for prop in account_info_dict: + print(" {}={}".format(prop, account_info_dict[prop])) +else: + print("failed to connect at account #{}, error code: {}".format(account, mt5.last_error())) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [initialize()](./initialize.md) +- [shutdown()](./shutdown.md) +- [account_info()](./account_info.md) \ No newline at end of file diff --git a/docs/mt5_reference/market_book_add.md b/docs/mt5_reference/market_book_add.md new file mode 100644 index 0000000..583c30f --- /dev/null +++ b/docs/mt5_reference/market_book_add.md @@ -0,0 +1,66 @@ +# market_book_add + +Subscribes the MetaTrader 5 terminal to the Market Depth change events for a specified symbol. + +## Syntax + +```python +market_book_add( + symbol # financial instrument name +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name. Required unnamed parameter. | + +## Return Value + +Returns True if successful, otherwise – False. + +## Note + +The function is similar to `MarketBookAdd` in MQL5. + +## Example + +```python +import MetaTrader5 as mt5 +import time + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# subscribe to market depth updates for EURUSD +if not mt5.market_book_add('EURUSD'): + print("Failed to subscribe to market depth for EURUSD, error code =", mt5.last_error()) + mt5.shutdown() + quit() + +# get market depth data +depth = mt5.market_book_get('EURUSD') +if depth is None: + print("No market depth data") +else: + print("Market depth for EURUSD:") + for item in depth: + print(item) + +# unsubscribe from market depth updates for EURUSD +mt5.market_book_release('EURUSD') + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[market_book_get](market_book_get.md), [market_book_release](market_book_release.md) \ No newline at end of file diff --git a/docs/mt5_reference/market_book_get.md b/docs/mt5_reference/market_book_get.md new file mode 100644 index 0000000..7591fd0 --- /dev/null +++ b/docs/mt5_reference/market_book_get.md @@ -0,0 +1,74 @@ +# market_book_get + +Returns a tuple from BookInfo featuring Market Depth entries for the specified symbol. + +## Syntax + +```python +market_book_get( + symbol # financial instrument name +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name. Required unnamed parameter. | + +## Return Value + +Returns the Market Depth content as a tuple from BookInfo entries featuring order type, price and volume in lots. BookInfo is similar to the MqlBookInfo structure. + +Returns None in case of an error. The info on the error can be obtained using [last_error](last_error.md). + +## Note + +The subscription to the Market Depth change events should be preliminarily performed using the [market_book_add](market_book_add.md) function. + +The function is similar to MarketBookGet in MQL5. + +## Example + +```python +import MetaTrader5 as mt5 +import time + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + # shut down connection to the MetaTrader 5 terminal + mt5.shutdown() + quit() + +# subscribe to market depth updates for EURUSD (Depth of Market) +if mt5.market_book_add('EURUSD'): + # get the market depth data 10 times in a loop + for i in range(10): + # get the market depth content (Depth of Market) + items = mt5.market_book_get('EURUSD') + # display the entire market depth 'as is' in a single string + print(items) + # now display each order separately for more clarity + if items: + for it in items: + # order content + print(it._asdict()) + # pause for 5 seconds before the next request of the market depth data + time.sleep(5) + # cancel the subscription to the market depth updates (Depth of Market) + mt5.market_book_release('EURUSD') +else: + print("mt5.market_book_add('EURUSD') failed, error code =", mt5.last_error()) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[market_book_add](market_book_add.md), [market_book_release](market_book_release.md) \ No newline at end of file diff --git a/docs/mt5_reference/market_book_release.md b/docs/mt5_reference/market_book_release.md new file mode 100644 index 0000000..d985681 --- /dev/null +++ b/docs/mt5_reference/market_book_release.md @@ -0,0 +1,70 @@ +# market_book_release + +Cancels subscription of the MetaTrader 5 terminal to the Market Depth change events for a specified symbol. + +## Syntax + +```python +market_book_release( + symbol # financial instrument name +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name. Required unnamed parameter. | + +## Return Value + +Returns True if successful, otherwise – False. + +## Note + +The function is similar to MarketBookRelease in MQL5. + +## Example + +```python +import MetaTrader5 as mt5 +import time + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + # shut down connection to the MetaTrader 5 terminal + mt5.shutdown() + quit() + +# subscribe to market depth updates for EURUSD (Depth of Market) +if mt5.market_book_add('EURUSD'): + # get the market depth data 10 times in a loop + for i in range(10): + # get the market depth content (Depth of Market) + items = mt5.market_book_get('EURUSD') + # display the entire market depth 'as is' in a single string + print(items) + # now display each order separately for more clarity + if items: + for it in items: + # order content + print(it._asdict()) + # pause for 5 seconds before the next request of the market depth data + time.sleep(5) + # cancel the subscription to the market depth updates (Depth of Market) + mt5.market_book_release('EURUSD') +else: + print("mt5.market_book_add('EURUSD') failed, error code =", mt5.last_error()) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[market_book_add](market_book_add.md), [market_book_get](market_book_get.md) \ No newline at end of file diff --git a/docs/mt5_reference/order_calc_margin.md b/docs/mt5_reference/order_calc_margin.md new file mode 100644 index 0000000..3410d00 --- /dev/null +++ b/docs/mt5_reference/order_calc_margin.md @@ -0,0 +1,97 @@ +# order_calc_margin + +Return margin in the account currency to perform a specified trading operation. + +## Syntax + +```python +order_calc_margin( + action, # order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL) + symbol, # symbol name + volume, # volume + price # open price +) +``` + +## Parameters + +- `action` (ORDER_TYPE) + - Order type taking values from the ORDER_TYPE enumeration. Required unnamed parameter. + +- `symbol` (str) + - Financial instrument name. Required unnamed parameter. + +- `volume` (float) + - Trading operation volume. Required unnamed parameter. + +- `price` (float) + - Open price. Required unnamed parameter. + +## Return Value + +Real value if successful, otherwise None. The error info can be obtained using `last_error()`. + +## Notes + +The function allows estimating the margin necessary for a specified order type on the current account and in the current market environment without considering the current pending orders and open positions. The function is similar to OrderCalcMargin. + +## ORDER_TYPE Enumeration + +- `ORDER_TYPE_BUY` - Market buy order +- `ORDER_TYPE_SELL` - Market sell order +- `ORDER_TYPE_BUY_LIMIT` - Buy Limit pending order +- `ORDER_TYPE_SELL_LIMIT` - Sell Limit pending order +- `ORDER_TYPE_BUY_STOP` - Buy Stop pending order +- `ORDER_TYPE_SELL_STOP` - Sell Stop pending order +- `ORDER_TYPE_BUY_STOP_LIMIT` - Upon reaching the order price, Buy Limit pending order is placed at StopLimit price +- `ORDER_TYPE_SELL_STOP_LIMIT` - Upon reaching the order price, Sell Limit pending order is placed at StopLimit price +- `ORDER_TYPE_CLOSE_BY` - Order for closing a position by an opposite one + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ",mt5.__author__) +print("MetaTrader5 package version: ",mt5.__version__) + +# establish connection to MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =",mt5.last_error()) + quit() + +# get account currency +account_currency=mt5.account_info().currency +print("Account currency:",account_currency) + +# arrange the symbol list +symbols=("EURUSD","GBPUSD","USDJPY", "USDCHF","EURJPY","GBPJPY") +print("Symbols to check margin:", symbols) +action=mt5.ORDER_TYPE_BUY +lot=0.1 +for symbol in symbols: + symbol_info=mt5.symbol_info(symbol) + if symbol_info is None: + print(symbol,"not found, skipped") + continue + if not symbol_info.visible: + print(symbol, "is not visible, trying to switch on") + if not mt5.symbol_select(symbol,True): + print("symbol_select({}}) failed, skipped",symbol) + continue + ask=mt5.symbol_info_tick(symbol).ask + margin=mt5.order_calc_margin(action,symbol,lot,ask) + if margin != None: + print(" {} buy {} lot margin: {} {}".format(symbol,lot,margin,account_currency)); + else: + print("order_calc_margin failed: , error code = ", mt5.last_error()) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [order_calc_profit](order_calc_profit.md) +- [order_check](order_check.md) \ No newline at end of file diff --git a/docs/mt5_reference/order_calc_profit.md b/docs/mt5_reference/order_calc_profit.md new file mode 100644 index 0000000..f90d510 --- /dev/null +++ b/docs/mt5_reference/order_calc_profit.md @@ -0,0 +1,99 @@ +# order_calc_profit + +Return profit in the account currency for a specified trading operation. + +## Syntax + +```python +order_calc_profit( + action, # order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL) + symbol, # symbol name + volume, # volume + price_open, # open price + price_close # close price +) +``` + +## Parameters + +- `action` (ORDER_TYPE) + - Order type may take one of the two ORDER_TYPE enumeration values: ORDER_TYPE_BUY or ORDER_TYPE_SELL. Required unnamed parameter. + +- `symbol` (str) + - Financial instrument name. Required unnamed parameter. + +- `volume` (float) + - Trading operation volume. Required unnamed parameter. + +- `price_open` (float) + - Open price. Required unnamed parameter. + +- `price_close` (float) + - Close price. Required unnamed parameter. + +## Return Value + +Real value if successful, otherwise None. The error info can be obtained using `last_error()`. + +## Notes + +The function allows estimating a trading operation result on the current account and in the current trading environment. The function is similar to OrderCalcProfit. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ",mt5.__author__) +print("MetaTrader5 package version: ",mt5.__version__) + +# establish connection to MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =",mt5.last_error()) + quit() + +# get account currency +account_currency=mt5.account_info().currency +print("Account currency:",account_currency) + +# arrange the symbol list +symbols=("EURUSD","GBPUSD","USDJPY") +print("Symbols to check margin:", symbols) + +lot=1.0 +distance=300 +for symbol in symbols: + symbol_info=mt5.symbol_info(symbol) + if symbol_info is None: + print(symbol,"not found, skipped") + continue + if not symbol_info.visible: + print(symbol, "is not visible, trying to switch on") + if not mt5.symbol_select(symbol,True): + print("symbol_select({}}) failed, skipped",symbol) + continue + point=mt5.symbol_info(symbol).point + symbol_tick=mt5.symbol_info_tick(symbol) + ask=symbol_tick.ask + bid=symbol_tick.bid + buy_profit=mt5.order_calc_profit(mt5.ORDER_TYPE_BUY,symbol,lot,ask,ask+distance*point) + if buy_profit!=None: + print(" buy {} {} lot: profit on {} points => {} {}".format(symbol,lot,distance,buy_profit,account_currency)); + else: + print("order_calc_profit(ORDER_TYPE_BUY) failed, error code = ",mt5.last_error()) + sell_profit=mt5.order_calc_profit(mt5.ORDER_TYPE_SELL,symbol,lot,bid,bid-distance*point) + if sell_profit!=None: + print(" sell {} {} lots: profit on {} points => {} {}".format(symbol,lot,distance,sell_profit,account_currency)); + else: + print("order_calc_profit(ORDER_TYPE_SELL) failed, error code = ",mt5.last_error()) + print() + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [order_calc_margin](order_calc_margin.md) +- [order_check](order_check.md) \ No newline at end of file diff --git a/docs/mt5_reference/order_check.md b/docs/mt5_reference/order_check.md new file mode 100644 index 0000000..51b44cf --- /dev/null +++ b/docs/mt5_reference/order_check.md @@ -0,0 +1,160 @@ +# order_check() + +Checks funds sufficiency for performing a required trading operation. The check result is returned as an MqlTradeCheckResult structure. + +## Syntax + +```python +order_check( + request # trading request structure +) +``` + +## Parameters + +`request` [in] - MqlTradeRequest type structure describing the required trading action. Required unnamed parameter. + +The trading request structure has the following fields: + +| Field | Description | +|-------|-------------| +| action | Trading operation type. Can be one of the TRADE_REQUEST_ACTIONS values | +| magic | EA ID. Allows arranging analytical handling of trading orders | +| order | Order ticket. Required for modifying pending orders | +| symbol | Trading instrument name. Not required when modifying orders and closing positions | +| volume | Requested volume in lots | +| price | Price at which to execute the order | +| stoplimit | Price for pending Limit order when price reaches the 'price' value | +| sl | Stop Loss price | +| tp | Take Profit price | +| deviation | Maximum acceptable deviation from requested price (in points) | +| type | Order type. Can be one of the ORDER_TYPE values | +| type_filling | Order filling type. Can be one of the ORDER_TYPE_FILLING values | +| type_time | Order type by expiration. Can be one of the ORDER_TYPE_TIME values | +| expiration | Pending order expiration time (for TIME_SPECIFIED type orders) | +| comment | Order comment | +| position | Position ticket for position modification/closure | +| position_by | Opposite position ticket for closing by an opposite position | + +### TRADE_REQUEST_ACTIONS Values + +| ID | Description | +|----|-------------| +| TRADE_ACTION_DEAL | Place an order for an instant deal with the specified parameters (set a market order) | +| TRADE_ACTION_PENDING | Place an order for performing a deal at specified conditions (pending order) | +| TRADE_ACTION_SLTP | Change open position Stop Loss and Take Profit | +| TRADE_ACTION_MODIFY | Change parameters of the previously placed trading order | +| TRADE_ACTION_REMOVE | Remove previously placed pending order | +| TRADE_ACTION_CLOSE_BY | Close a position by an opposite one | + +### ORDER_TYPE_FILLING Values + +| ID | Description | +|----|-------------| +| ORDER_FILLING_FOK | Fill or Kill - can be executed only in the specified volume. If the necessary amount is currently unavailable, the order will not be executed | +| ORDER_FILLING_IOC | Immediate or Cancel - execute a deal with the volume available in the market within the specified volume. If the request cannot be filled completely, an order with the available volume will be executed | +| ORDER_FILLING_RETURN | This policy is used for market/limit/stop limit orders in Market or Exchange execution modes. Any unfilled volume will remain active | + +### ORDER_TYPE_TIME Values + +| ID | Description | +|----|-------------| +| ORDER_TIME_GTC | Good Till Cancelled - order stays in the queue until manually cancelled | +| ORDER_TIME_DAY | Good Till Day - order is active only during the current trading day | +| ORDER_TIME_SPECIFIED | Good Till Specified - order is active until the specified date | +| ORDER_TIME_SPECIFIED_DAY | Good Till Specified Day - order is active until 23:59:59 of the specified day | + +## Return Value + +Returns the result as an MqlTradeCheckResult structure containing: +- retcode: Operation return code +- balance: Balance value after the execution of the deal +- equity: Equity value after the execution of the deal +- profit: Floating profit value +- margin: Margin requirements for the deal +- margin_free: Free margin remaining after the execution of the deal +- margin_level: Margin level after the execution of the deal +- comment: Comment on the check result +- request: The structure of the trading request passed to order_check() + +Returns None in case of error. The error info can be obtained using [last_error()](./last_error.md). + +## Note + +Successful check of a request **does not guarantee that the requested trading operation will be executed successfully**. The order_check() function is similar to OrderCheck in MQL5. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# get account currency +account_currency=mt5.account_info().currency +print("Account currency:", account_currency) + +# prepare the request +symbol="USDJPY" +symbol_info = mt5.symbol_info(symbol) +if symbol_info is None: + print(symbol, "not found, can not call order_check()") + mt5.shutdown() + quit() + +# if the symbol is unavailable in MarketWatch, add it +if not symbol_info.visible: + print(symbol, "is not visible, trying to switch on") + if not mt5.symbol_select(symbol, True): + print("symbol_select({}) failed, exit".format(symbol)) + mt5.shutdown() + quit() + +# prepare the request +point = mt5.symbol_info(symbol).point +request = { + "action": mt5.TRADE_ACTION_DEAL, + "symbol": symbol, + "volume": 1.0, + "type": mt5.ORDER_TYPE_BUY, + "price": mt5.symbol_info_tick(symbol).ask, + "sl": mt5.symbol_info_tick(symbol).ask-100*point, + "tp": mt5.symbol_info_tick(symbol).ask+100*point, + "deviation": 10, + "magic": 234000, + "comment": "python script", + "type_time": mt5.ORDER_TIME_GTC, + "type_filling": mt5.ORDER_FILLING_RETURN, +} + +# perform the check and display the result 'as is' +result = mt5.order_check(request) +print(result); + +# request the result as a dictionary and display it element by element +result_dict=result._asdict() +for field in result_dict.keys(): + print(" {}={}".format(field,result_dict[field])) + # if this is a trading request structure, display it element by element as well + if field=="request": + traderequest_dict=result_dict[field]._asdict() + for tradereq_filed in traderequest_dict: + print(" traderequest: {}={}".format(tradereq_filed,traderequest_dict[tradereq_filed])) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [order_send()](./order_send.md) +- [order_calc_margin()](./order_calc_margin.md) +- [order_calc_profit()](./order_calc_profit.md) +- [positions_get()](./positions_get.md) \ No newline at end of file diff --git a/docs/mt5_reference/order_send.md b/docs/mt5_reference/order_send.md new file mode 100644 index 0000000..e1ad978 --- /dev/null +++ b/docs/mt5_reference/order_send.md @@ -0,0 +1,137 @@ +# order_send() + +Sends a trading request to perform a trading operation from the terminal to the trade server. + +## Syntax + +```python +order_send( + request # trading request structure +) +``` + +## Parameters + +`request` [in] - MqlTradeRequest type structure describing the required trading action. Required unnamed parameter. + +The trading request structure has the following fields: + +| Field | Description | +|-------|-------------| +| action | Trading operation type. Can be one of the TRADE_REQUEST_ACTIONS values | +| magic | EA ID. Allows arranging analytical handling of trading orders | +| order | Order ticket. Required for modifying pending orders | +| symbol | Trading instrument name. Not required when modifying orders and closing positions | +| volume | Requested volume in lots | +| price | Price at which to execute the order | +| stoplimit | Price for pending Limit order when price reaches the 'price' value | +| sl | Stop Loss price | +| tp | Take Profit price | +| deviation | Maximum acceptable deviation from requested price (in points) | +| type | Order type. Can be one of the ORDER_TYPE values | +| type_filling | Order filling type. Can be one of the ORDER_TYPE_FILLING values | +| type_time | Order type by expiration. Can be one of the ORDER_TYPE_TIME values | +| expiration | Pending order expiration time (for TIME_SPECIFIED type orders) | +| comment | Order comment | +| position | Position ticket for position modification/closure | +| position_by | Opposite position ticket for closing by an opposite position | + +## Return Value + +Returns the result as an MqlTradeResult structure containing: +- retcode: Operation return code +- deal: Deal ticket if executed +- order: Order ticket +- volume: Deal volume confirmed by broker +- price: Deal price confirmed by broker +- bid: Current bid price +- ask: Current ask price +- comment: Broker comment on operation +- request_id: Request ID set by terminal during dispatch +- retcode_external: Return code of external trading system +- request: The structure of the trading request passed to order_send() + +Returns None in case of error. The error info can be obtained using [last_error()](./last_error.md). + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# prepare the buy request structure +symbol = "USDJPY" +symbol_info = mt5.symbol_info(symbol) +if symbol_info is None: + print(symbol, "not found, can not call order_check()") + mt5.shutdown() + quit() + +# if the symbol is unavailable in MarketWatch, add it +if not symbol_info.visible: + print(symbol, "is not visible, trying to switch on") + if not mt5.symbol_select(symbol, True): + print("symbol_select({}) failed, exit".format(symbol)) + mt5.shutdown() + quit() + +lot = 0.1 +point = mt5.symbol_info(symbol).point +price = mt5.symbol_info_tick(symbol).ask +deviation = 20 +request = { + "action": mt5.TRADE_ACTION_DEAL, + "symbol": symbol, + "volume": lot, + "type": mt5.ORDER_TYPE_BUY, + "price": price, + "sl": price - 100 * point, + "tp": price + 100 * point, + "deviation": deviation, + "magic": 234000, + "comment": "python script open", + "type_time": mt5.ORDER_TIME_GTC, + "type_filling": mt5.ORDER_FILLING_RETURN, +} + +# send a trading request +result = mt5.order_send(request) + +# check the execution result +print("1. order_send(): by {} {} lots at {} with deviation={} points".format(symbol, lot, price, deviation)); +if result.retcode != mt5.TRADE_RETCODE_DONE: + print("2. order_send failed, retcode={}".format(result.retcode)) + # request the result as a dictionary and display it element by element + result_dict = result._asdict() + for field in result_dict.keys(): + print(" {}={}".format(field, result_dict[field])) + # if this is a trading request structure, display it element by element as well + if field=="request": + traderequest_dict = result_dict[field]._asdict() + for tradereq_filed in traderequest_dict: + print(" traderequest: {}={}".format(tradereq_filed, traderequest_dict[tradereq_filed])) + print("shutdown() and quit") + mt5.shutdown() + quit() + +print("2. order_send done, ", result) +print(" opened position with POSITION_TICKET={}".format(result.order)) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [order_check()](./order_check.md) +- [positions_get()](./positions_get.md) +- [history_orders_get()](./history_orders_get.md) +- [history_deals_get()](./history_deals_get.md) \ No newline at end of file diff --git a/docs/mt5_reference/orders_get.md b/docs/mt5_reference/orders_get.md new file mode 100644 index 0000000..fbe5ad4 --- /dev/null +++ b/docs/mt5_reference/orders_get.md @@ -0,0 +1,98 @@ +# orders_get + +Get active orders with the ability to filter by symbol or ticket. There are three call options. + +## Syntax + +```python +# Get active orders on all symbols +orders_get() + +# Get active orders for a specified symbol +orders_get( + symbol="SYMBOL" # symbol name +) + +# Get active orders for a group of symbols +orders_get( + group="GROUP" # filter for selecting orders for symbols +) + +# Get active order by ticket +orders_get( + ticket=TICKET # ticket +) +``` + +## Parameters + +- `symbol` (str, optional) + - Symbol name. If specified, the `ticket` parameter is ignored. + +- `group` (str, optional) + - Filter for arranging a group of necessary symbols. If specified, the function returns only active orders meeting the specified criteria for symbol names. + - Can use '*' at the beginning and end of the string + - Can contain several comma-separated conditions + - Conditions can be set as masks using '*' + - The logical negation symbol '!' can be used for exclusion + - Example: `group="*, !EUR"` means select orders for all symbols first, then exclude ones containing "EUR" + +- `ticket` (int, optional) + - Order ticket (ORDER_TICKET) + +## Return Value + +Returns info in the form of a named tuple structure (namedtuple). Returns None in case of an error. The info on the error can be obtained using `last_error()`. + +## Notes + +The function allows receiving all active orders within one call similar to the OrdersTotal and OrderSelect tandem. + +## Example + +```python +import MetaTrader5 as mt5 +import pandas as pd +pd.set_option('display.max_columns', 500) # number of columns to be displayed +pd.set_option('display.width', 1500) # max table width to display + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ",mt5.__author__) +print("MetaTrader5 package version: ",mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =",mt5.last_error()) + quit() + +# display data on active orders on GBPUSD +orders=mt5.orders_get(symbol="GBPUSD") +if orders is None: + print("No orders on GBPUSD, error code={}".format(mt5.last_error())) +else: + print("Total orders on GBPUSD:",len(orders)) + # display all active orders + for order in orders: + print(order) +print() + +# get the list of orders on symbols whose names contain "*GBP*" +gbp_orders=mt5.orders_get(group="*GBP*") +if gbp_orders is None: + print("No orders with group=\"*GBP*\", error code={}".format(mt5.last_error())) +else: + print("orders_get(group=\"*GBP*\")={}".format(len(gbp_orders))) + # display these orders as a table using pandas.DataFrame + df=pd.DataFrame(list(gbp_orders),columns=gbp_orders[0]._asdict().keys()) + df.drop(['time_done', 'time_done_msc', 'position_id', 'position_by_id', 'reason', 'volume_initial', 'price_stoplimit'], axis=1, inplace=True) + df['time_setup'] = pd.to_datetime(df['time_setup'], unit='s') + print(df) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [orders_total](orders_total.md) +- [positions_get](positions_get.md) \ No newline at end of file diff --git a/docs/mt5_reference/orders_total.md b/docs/mt5_reference/orders_total.md new file mode 100644 index 0000000..8cc7e0d --- /dev/null +++ b/docs/mt5_reference/orders_total.md @@ -0,0 +1,52 @@ +# orders_total + +Get the number of active orders. + +## Syntax + +```python +orders_total() +``` + +## Parameters + +None. + +## Return Value + +Returns an integer value representing the number of active orders. + +Returns None in case of an error. The info on the error can be obtained using [last_error()](./last_error.md). + +## Note + +The function is similar to OrdersTotal in MQL5. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# check the presence of active orders +orders = mt5.orders_total() +if orders > 0: + print("Total orders=", orders) +else: + print("Orders not found") + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[orders_get](./orders_get.md), [positions_total](./positions_total.md) \ No newline at end of file diff --git a/docs/mt5_reference/positions_get.md b/docs/mt5_reference/positions_get.md new file mode 100644 index 0000000..e47dcbe --- /dev/null +++ b/docs/mt5_reference/positions_get.md @@ -0,0 +1,122 @@ +# positions_get() + +Get open positions with the ability to filter by symbol or ticket. There are three call options. + +## Syntax + +1. Call without parameters to return open positions for all symbols: +```python +positions_get() +``` + +2. Call specifying a symbol to get open positions for: +```python +positions_get( + symbol="SYMBOL" # symbol name +) +``` + +3. Call specifying a group of symbols to filter positions by: +```python +positions_get( + group="GROUP" # filter for selecting positions by symbols +) +``` + +4. Call specifying a position ticket: +```python +positions_get( + ticket=TICKET # ticket +) +``` + +## Parameters + +- `symbol` [in] - Symbol name. Optional named parameter. If a symbol is specified, the ticket parameter is ignored. +- `group` [in] - The filter for arranging a group of necessary symbols. Optional named parameter. If the group is specified, the function returns only positions meeting the specified criteria for symbol names. +- `ticket` [in] - Position ticket (POSITION_TICKET). Optional named parameter. + +### Group Filter Format + +The `group` parameter may contain several comma-separated conditions: +- Use '*' as a mask in a condition +- Use '!' for logical negation +- Conditions are applied sequentially +- Include conditions should be specified first, followed by exclusion conditions + +Example: `group="*, !EUR"` means select positions for all symbols first, then exclude ones containing "EUR" in symbol names. + +## Return Value + +Returns info in the form of a named tuple structure (namedtuple) containing: +- ticket: Position ticket +- time: Position opening time +- type: Position type (0 - buy, 1 - sell) +- magic: Position magic number +- identifier: Position identifier +- reason: Position opening reason +- volume: Position volume +- price_open: Position opening price +- sl: Stop Loss level +- tp: Take Profit level +- price_current: Current price +- swap: Cumulative swap +- profit: Current profit +- symbol: Position symbol +- comment: Position comment + +Returns None in case of error. The error info can be obtained using [last_error()](./last_error.md). + +## Note + +The function allows receiving all open positions within one call similar to the PositionsTotal and PositionSelect tandem in MQL5. + +## Example + +```python +import MetaTrader5 as mt5 +import pandas as pd +pd.set_option('display.max_columns', 500) # number of columns to be displayed +pd.set_option('display.width', 1500) # max table width to display + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# get open positions on USDCHF +positions = mt5.positions_get(symbol="USDCHF") +if positions is None: + print("No positions on USDCHF, error code={}".format(mt5.last_error())) +elif len(positions) > 0: + print("Total positions on USDCHF =", len(positions)) + # display all open positions + for position in positions: + print(position) + +# get the list of positions on symbols whose names contain "*USD*" +usd_positions = mt5.positions_get(group="*USD*") +if usd_positions is None: + print("No positions with group=\"*USD*\", error code={}".format(mt5.last_error())) +elif len(usd_positions) > 0: + print("positions_get(group=\"*USD*\")={}".format(len(usd_positions))) + # display these positions as a table using pandas.DataFrame + df = pd.DataFrame(list(usd_positions), columns=usd_positions[0]._asdict().keys()) + df['time'] = pd.to_datetime(df['time'], unit='s') + df.drop(['time_update', 'time_msc', 'time_update_msc', 'external_id'], axis=1, inplace=True) + print(df) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [positions_total()](./positions_total.md) +- [orders_get()](./orders_get.md) +- [history_orders_get()](./history_orders_get.md) +- [history_deals_get()](./history_deals_get.md) \ No newline at end of file diff --git a/docs/mt5_reference/shutdown.md b/docs/mt5_reference/shutdown.md new file mode 100644 index 0000000..0b6dd75 --- /dev/null +++ b/docs/mt5_reference/shutdown.md @@ -0,0 +1,47 @@ +# shutdown() + +Closes the previously established connection to the MetaTrader 5 terminal. + +## Syntax + +```python +shutdown() +``` + +## Parameters + +None + +## Return Value + +None + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed") + quit() + +# display data on connection status, server name and trading account +print(mt5.terminal_info()) +# display data on MetaTrader 5 version +print(mt5.version()) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [initialize()](./initialize.md) +- [login()](./login.md) +- [terminal_info()](./terminal_info.md) +- [version()](./version.md) \ No newline at end of file diff --git a/docs/mt5_reference/symbol_info.md b/docs/mt5_reference/symbol_info.md new file mode 100644 index 0000000..5b6f19e --- /dev/null +++ b/docs/mt5_reference/symbol_info.md @@ -0,0 +1,99 @@ +# symbol_info + +Get data on the specified financial instrument. + +## Syntax + +```python +symbol_info( + symbol # financial instrument name +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name. Required unnamed parameter. | + +## Return Value + +Return info in the form of a named tuple structure (namedtuple) containing symbol properties. The tuple includes fields like: + +- `custom` - Custom symbol flag +- `chart_mode` - Price type for constructing bars +- `select` - Symbol selection in Market Watch +- `visible` - Symbol visibility in Market Watch +- `session_deals` - Number of deals in the current session +- `session_buy_orders` - Number of Buy orders at the moment +- `session_sell_orders` - Number of Sell orders at the moment +- `volume` - Last deal volume +- `volumehigh` - Maximum volume for the day +- `volumelow` - Minimum volume for the day +- `time` - Time of the last quote +- `digits` - Number of decimal places +- `spread` - Spread value in points +- `spread_float` - Floating spread flag +- `trade_calc_mode` - Contract price calculation mode +- `trade_mode` - Order execution type +- `bid` - Current Bid price +- `ask` - Current Ask price +- `point` - Symbol point value +- `trade_tick_value` - Value of TRADE_TICK_VALUE +- `trade_tick_size` - Minimal price change +- `trade_contract_size` - Trade contract size +- `volume_min` - Minimal volume for a deal +- `volume_max` - Maximal volume for a deal +- `volume_step` - Minimal volume change step for deal execution +- `currency_base` - Basic currency of a symbol +- `currency_profit` - Profit currency +- `currency_margin` - Margin currency +- `description` - Symbol description +- `path` - Path in the symbol tree + +Returns None in case of an error. The info on the error can be obtained using `last_error()`. + +## Note + +The function returns all data that can be obtained using `SymbolInfoInteger`, `SymbolInfoDouble` and `SymbolInfoString` in one call. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# attempt to enable the display of the EURJPY symbol in MarketWatch +selected = mt5.symbol_select("EURJPY", True) +if not selected: + print("Failed to select EURJPY") + mt5.shutdown() + quit() + +# display EURJPY symbol properties +symbol_info = mt5.symbol_info("EURJPY") +if symbol_info != None: + # display the terminal data 'as is' + print(symbol_info) + print("EURJPY: spread =", symbol_info.spread, " digits =", symbol_info.digits) + # display symbol properties as a list + print("Show symbol_info(\"EURJPY\")._asdict():") + symbol_info_dict = mt5.symbol_info("EURJPY")._asdict() + for prop in symbol_info_dict: + print(" {}={}".format(prop, symbol_info_dict[prop])) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[symbols_total](symbols_total.md), [symbols_get](symbols_get.md), [symbol_select](symbol_select.md) \ No newline at end of file diff --git a/docs/mt5_reference/symbol_info_tick.md b/docs/mt5_reference/symbol_info_tick.md new file mode 100644 index 0000000..80975bf --- /dev/null +++ b/docs/mt5_reference/symbol_info_tick.md @@ -0,0 +1,74 @@ +# symbol_info_tick + +Get the last tick for the specified financial instrument. + +## Syntax + +```python +symbol_info_tick( + symbol # financial instrument name +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name. Required unnamed parameter. | + +## Return Value + +Return info in the form of a named tuple structure (namedtuple) containing the following fields: + +- `time` - Time of the last quote (in seconds) +- `bid` - Current Bid price +- `ask` - Current Ask price +- `last` - Price of the last deal (Last) +- `volume` - Volume for the current Last price +- `time_msc` - Time of the last quote in milliseconds +- `flags` - Tick flags +- `volume_real` - Volume for the current Last price with greater accuracy + +Returns None in case of an error. The info on the error can be obtained using `last_error()`. + +## Note + +The function is similar to `SymbolInfoTick` in MQL5. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# attempt to enable the display of the GBPUSD in MarketWatch +selected = mt5.symbol_select("GBPUSD", True) +if not selected: + print("Failed to select GBPUSD") + mt5.shutdown() + quit() + +# display the last GBPUSD tick +lasttick = mt5.symbol_info_tick("GBPUSD") +print(lasttick) +# display tick field values in the form of a list +print("Show symbol_info_tick(\"GBPUSD\")._asdict():") +symbol_info_tick_dict = mt5.symbol_info_tick("GBPUSD")._asdict() +for prop in symbol_info_tick_dict: + print(" {}={}".format(prop, symbol_info_tick_dict[prop])) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[symbol_info](symbol_info.md), [symbol_select](symbol_select.md) \ No newline at end of file diff --git a/docs/mt5_reference/symbol_select.md b/docs/mt5_reference/symbol_select.md new file mode 100644 index 0000000..5398b55 --- /dev/null +++ b/docs/mt5_reference/symbol_select.md @@ -0,0 +1,58 @@ +# symbol_select + +Select a symbol in the MarketWatch window or remove a symbol from the window. + +## Syntax + +```python +symbol_select( + symbol, # financial instrument name + enable=None # enable or disable +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| symbol | str | Financial instrument name. Required unnamed parameter. | +| enable | bool | Optional unnamed parameter. If 'false', a symbol should be removed from the MarketWatch window. Otherwise, it should be selected in the MarketWatch window. A symbol cannot be removed if open charts with this symbol are currently present or positions are opened on it. | + +## Return Value + +Returns True if successful, otherwise – False. + +## Note + +The function is similar to `SymbolSelect` in MQL5. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# attempt to enable the display of the EURCAD in MarketWatch +selected = mt5.symbol_select("EURCAD", True) +if not selected: + print("Failed to select EURCAD, error code =", mt5.last_error()) +else: + symbol_info = mt5.symbol_info("EURCAD") + print(symbol_info) + print("EURCAD: currency_base =", symbol_info.currency_base, " currency_profit =", symbol_info.currency_profit, " currency_margin =", symbol_info.currency_margin) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[symbol_info](symbol_info.md), [symbols_get](symbols_get.md) \ No newline at end of file diff --git a/docs/mt5_reference/symbols_get.md b/docs/mt5_reference/symbols_get.md new file mode 100644 index 0000000..d0adfe1 --- /dev/null +++ b/docs/mt5_reference/symbols_get.md @@ -0,0 +1,79 @@ +# symbols_get + +Get all financial instruments from the MetaTrader 5 terminal. + +## Syntax + +```python +symbols_get( + group="GROUP" # symbol selection filter +) +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| group | str | The filter for arranging a group of necessary symbols. Optional parameter. If the group is specified, the function returns only symbols meeting the specified criteria. | + +## Return Value + +Return symbols in the form of a tuple. Each symbol is represented as a named tuple structure containing symbol properties. + +Returns None in case of an error. The info on the error can be obtained using `last_error()`. + +## Note + +The `group` parameter allows sorting out symbols by name. '*' can be used at the beginning and the end of a string. + +The `group` parameter can be used as a named or an unnamed one. Both options work the same way. The named option (group="GROUP") makes the code easier to read. + +The `group` parameter may contain several comma separated conditions. A condition can be set as a mask using '*'. The logical negation symbol '!' can be used for an exclusion. All conditions are applied sequentially, which means conditions of including to a group should be specified first followed by an exclusion condition. For example, group="*, !EUR" means that all symbols should be selected first and the ones containing "EUR" in their names should be excluded afterwards. + +Unlike `symbol_info()`, the `symbols_get()` function returns data on all requested symbols within a single call. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# get all symbols +symbols = mt5.symbols_get() +print('Symbols: ', len(symbols)) +count = 0 +# display the first five ones +for s in symbols: + count += 1 + print("{}. {}".format(count, s.name)) + if count == 5: break +print() + +# get symbols containing RU in their names +ru_symbols = mt5.symbols_get("*RU*") +print('len(*RU*): ', len(ru_symbols)) +for s in ru_symbols: + print(s.name) +print() + +# get symbols whose names do not contain USD, EUR, JPY and GBP +group_symbols = mt5.symbols_get(group="*,!*USD*,!*EUR*,!*JPY*,!*GBP*") +print('len(*,!*USD*,!*EUR*,!*JPY*,!*GBP*):', len(group_symbols)) +for s in group_symbols: + print(s.name, ":", s) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[symbols_total](symbols_total.md), [symbol_select](symbol_select.md), [symbol_info](symbol_info.md) \ No newline at end of file diff --git a/docs/mt5_reference/symbols_total.md b/docs/mt5_reference/symbols_total.md new file mode 100644 index 0000000..6b8db46 --- /dev/null +++ b/docs/mt5_reference/symbols_total.md @@ -0,0 +1,48 @@ +# symbols_total + +Get the number of all financial instruments in the MetaTrader 5 terminal. + +## Syntax + +```python +symbols_total() +``` + +## Return Value + +Integer value representing the total number of financial instruments. + +Returns None in case of an error. The info on the error can be obtained using `last_error()`. + +## Note + +The function returns the number of all symbols including custom ones and the ones disabled in MarketWatch. + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# get the number of financial instruments +symbols = mt5.symbols_total() +if symbols > 0: + print("Total symbols =", symbols) +else: + print("symbols not found") + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[symbols_get](symbols_get.md), [symbol_select](symbol_select.md), [symbol_info](symbol_info.md) \ No newline at end of file diff --git a/docs/mt5_reference/terminal_info.md b/docs/mt5_reference/terminal_info.md new file mode 100644 index 0000000..a3bc784 --- /dev/null +++ b/docs/mt5_reference/terminal_info.md @@ -0,0 +1,86 @@ +# terminal_info + +Get the connected MetaTrader 5 client terminal status and settings. + +## Syntax + +```python +terminal_info() +``` + +## Return Value + +Return info in the form of a named tuple structure (namedtuple) with the following fields: + +| Field | Type | Description | +|-------|------|-------------| +| community_account | bool | Community account flag | +| community_connection | bool | Connection to MQL5.community status | +| connected | bool | Connection to a trade server status | +| dlls_allowed | bool | Permission to use DLL | +| trade_allowed | bool | Permission to trade | +| tradeapi_disabled | bool | Permission to use trading API | +| email_enabled | bool | Permission to send emails using SMTP-server and login specified in the terminal settings | +| ftp_enabled | bool | Permission to send reports using FTP-server and login specified in the terminal settings | +| notifications_enabled | bool | Permission to send notifications to smartphone | +| mqid | bool | Flag indicating presence of MetaQuotes ID data to send Push notifications | +| build | int | Client terminal build number | +| maxbars | int | Maximum bars count in charts | +| codepage | int | Code page of the language installed in the client terminal | +| ping_last | int | Last known value of ping to trade server in microseconds | +| community_balance | float | Community balance | +| retransmission | float | Connection data retransmission percentage | +| company | str | Company name | +| name | str | Terminal name | +| language | str | Language of terminal | +| path | str | Folder from which the terminal is started | +| data_path | str | Folder in which terminal data are stored | +| commondata_path | str | Common path for all terminals installed on a computer | + +Returns None in case of an error. The info on the error can be obtained using `last_error()`. + +## Note + +The function returns all data that can be obtained using TerminalInfoInteger, TerminalInfoDouble and TerminalInfoString in one call. + +## Example + +```python +import MetaTrader5 as mt5 +import pandas as pd + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# display info on MetaTrader 5 version +print(mt5.version()) + +# display info on the terminal settings and status +terminal_info = mt5.terminal_info() +if terminal_info != None: + # display the terminal data 'as is' + print(terminal_info) + # display data in the form of a list + print("Show terminal_info()._asdict():") + terminal_info_dict = mt5.terminal_info()._asdict() + for prop in terminal_info_dict: + print(" {}={}".format(prop, terminal_info_dict[prop])) + print() + # convert the dictionary into DataFrame and print + df = pd.DataFrame(list(terminal_info_dict.items()), columns=['property', 'value']) + print("terminal_info() as dataframe:") + print(df) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See also + +[initialize](initialize.md), [shutdown](shutdown.md), [version](version.md) \ No newline at end of file diff --git a/docs/mt5_reference/version.md b/docs/mt5_reference/version.md new file mode 100644 index 0000000..c8ead08 --- /dev/null +++ b/docs/mt5_reference/version.md @@ -0,0 +1,63 @@ +# version() + +Returns the MetaTrader 5 terminal version. + +## Syntax + +```python +version() +``` + +## Parameters + +None + +## Return Value + +Returns the MetaTrader 5 terminal version, build and release date as a tuple of three values: + +| Type | Description | Sample value | +|------|-------------|--------------| +| integer | MetaTrader 5 terminal version | 500 | +| integer | Build | 2007 | +| string | Build release date | '25 Feb 2019' | + +Returns None in case of an error. The info on the error can be obtained using [last_error()](./last_error.md). + +## Example + +```python +import MetaTrader5 as mt5 + +# display data on the MetaTrader 5 package +print("MetaTrader5 package author: ", mt5.__author__) +print("MetaTrader5 package version: ", mt5.__version__) + +# establish connection to the MetaTrader 5 terminal +if not mt5.initialize(): + print("initialize() failed, error code =", mt5.last_error()) + quit() + +# display data on MetaTrader 5 version +print(mt5.version()) + +# display data on connection status, server name and trading account 'as is' +print(mt5.terminal_info()) +print() + +# get properties in the form of a dictionary +terminal_info_dict = mt5.terminal_info()._asdict() +# convert the dictionary into DataFrame and print +df = pd.DataFrame(list(terminal_info_dict.items()), columns=['property', 'value']) +print("terminal_info() as dataframe:") +print(df[:-1]) + +# shut down connection to the MetaTrader 5 terminal +mt5.shutdown() +``` + +## See Also + +- [initialize()](./initialize.md) +- [shutdown()](./shutdown.md) +- [terminal_info()](./terminal_info.md) \ No newline at end of file diff --git a/generate_proto.sh b/generate_proto.sh index 867d1e9..ca3ffa0 100644 --- a/generate_proto.sh +++ b/generate_proto.sh @@ -1,6 +1,10 @@ #!/bin/bash -mkdir -p generated - python -m grpc_tools.protoc -I=protos --python_out=generated --grpc_python_out=generated protos/*.proto +python -m grpc_tools.protoc -I=protos --python_out=mt5_grpc_proto/mt5_grpc_proto --grpc_python_out=mt5_grpc_proto/mt5_grpc_proto protos/*.proto -echo "Proto files have been successfully compiled to Python files in the 'generated' directory." \ No newline at end of file +# Update import statements in generated Python files +for file in mt5_grpc_proto/*.py; do + sed -i '' 's/^\(import \)\(.*_pb2 as .*__pb2\)/from . import \2/' "$file" +done + +echo "Proto files have been successfully compiled to Python files." \ No newline at end of file diff --git a/generated/__init__.py b/generated/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/imp/__init__.py b/imp/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mt5_grpc_proto/MANIFEST.in b/mt5_grpc_proto/MANIFEST.in new file mode 100644 index 0000000..7f4c22a --- /dev/null +++ b/mt5_grpc_proto/MANIFEST.in @@ -0,0 +1,8 @@ +include LICENSE +include README.md +include requirements.txt +recursive-include mt5_grpc_proto *.py +recursive-include mt5_grpc_proto *.proto +global-exclude *.pyc +global-exclude __pycache__ +global-exclude .DS_Store \ No newline at end of file diff --git a/mt5_grpc_proto/Readme.md b/mt5_grpc_proto/Readme.md new file mode 100644 index 0000000..8980384 --- /dev/null +++ b/mt5_grpc_proto/Readme.md @@ -0,0 +1,23 @@ +# MT5 gRPC Proto + +Protocol Buffers and gRPC service definitions for MetaTrader 5 RPC Server. + +## Overview +This module contains the Protocol Buffer definitions and generated gRPC service code for interacting with MetaTrader 5 through a gRPC interface. It provides the contract between the MT5 gRPC server and its clients. + +## Installatio n + +```bash +pip install mt5-grpc-proto +``` + +## Features + +The proto definitions cover the following MetaTrader 5 functionalities: +- Account operations +- Trading operations +- Market data retrieval +- Order management +- Position tracking +- Historical data access +- Terminal information \ No newline at end of file diff --git a/mt5_grpc_proto/mt5_grpc_proto/__init__.py b/mt5_grpc_proto/mt5_grpc_proto/__init__.py new file mode 100644 index 0000000..a1ae6a5 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/__init__.py @@ -0,0 +1,32 @@ +from .account_pb2 import * +from .account_pb2_grpc import * +from .common_pb2 import * +from .common_pb2_grpc import * +from .deal_pb2 import * +from .deal_pb2_grpc import * +from .history_orders_pb2 import * +from .history_orders_pb2_grpc import * +from .initialize_pb2 import * +from .initialize_pb2_grpc import * +from .market_book_pb2 import * +from .market_book_pb2_grpc import * +from .market_data_pb2 import * +from .market_data_pb2_grpc import * +from .order_calc_pb2 import * +from .order_calc_pb2_grpc import * +from .order_check_pb2 import * +from .order_check_pb2_grpc import * +from .order_pb2 import * +from .order_pb2_grpc import * +from .position_pb2 import * +from .position_pb2_grpc import * +from .symbol_info_pb2 import * +from .symbol_info_pb2_grpc import * +from .symbol_info_tick_pb2 import * +from .symbol_info_tick_pb2_grpc import * +from .symbols_pb2 import * +from .symbols_pb2_grpc import * +from .terminal_pb2 import * +from .terminal_pb2_grpc import * +from .trade_pb2 import * +from .trade_pb2_grpc import * \ No newline at end of file diff --git a/mt5_grpc_proto/mt5_grpc_proto/account_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/account_pb2.py new file mode 100644 index 0000000..cbd4483 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/account_pb2.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: account.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'account.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\raccount.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\"\xbf\x04\n\x0b\x41\x63\x63ountInfo\x12\r\n\x05login\x18\x01 \x01(\x03\x12\x12\n\ntrade_mode\x18\x02 \x01(\x05\x12\x10\n\x08leverage\x18\x03 \x01(\x05\x12\x14\n\x0climit_orders\x18\x04 \x01(\x05\x12\x16\n\x0emargin_so_mode\x18\x05 \x01(\x05\x12\x13\n\x0bmargin_mode\x18\x06 \x01(\x05\x12\x17\n\x0f\x63urrency_digits\x18\x07 \x01(\x05\x12\x15\n\rtrade_allowed\x18\n \x01(\x08\x12\x14\n\x0ctrade_expert\x18\x0b \x01(\x08\x12\x12\n\nfifo_close\x18\x0c \x01(\x08\x12\x0f\n\x07\x62\x61lance\x18\x14 \x01(\x01\x12\x0e\n\x06\x63redit\x18\x15 \x01(\x01\x12\x0e\n\x06profit\x18\x16 \x01(\x01\x12\x0e\n\x06\x65quity\x18\x17 \x01(\x01\x12\x0e\n\x06margin\x18\x18 \x01(\x01\x12\x13\n\x0bmargin_free\x18\x19 \x01(\x01\x12\x14\n\x0cmargin_level\x18\x1a \x01(\x01\x12\x16\n\x0emargin_so_call\x18\x1b \x01(\x01\x12\x14\n\x0cmargin_so_so\x18\x1c \x01(\x01\x12\x16\n\x0emargin_initial\x18\x1d \x01(\x01\x12\x1a\n\x12margin_maintenance\x18\x1e \x01(\x01\x12\x0e\n\x06\x61ssets\x18\x1f \x01(\x01\x12\x13\n\x0bliabilities\x18 \x01(\x01\x12\x1a\n\x12\x63ommission_blocked\x18! \x01(\x01\x12\x0c\n\x04name\x18( \x01(\t\x12\x0e\n\x06server\x18) \x01(\t\x12\x10\n\x08\x63urrency\x18* \x01(\t\x12\x0f\n\x07\x63ompany\x18+ \x01(\t\"\x14\n\x12\x41\x63\x63ountInfoRequest\"l\n\x13\x41\x63\x63ountInfoResponse\x12\x30\n\x0c\x61\x63\x63ount_info\x18\x01 \x01(\x0b\x32\x1a.metatrader.v1.AccountInfo\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2m\n\x12\x41\x63\x63ountInfoService\x12W\n\x0eGetAccountInfo\x12!.metatrader.v1.AccountInfoRequest\x1a\".metatrader.v1.AccountInfoResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'account_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_ACCOUNTINFO']._serialized_start=47 + _globals['_ACCOUNTINFO']._serialized_end=622 + _globals['_ACCOUNTINFOREQUEST']._serialized_start=624 + _globals['_ACCOUNTINFOREQUEST']._serialized_end=644 + _globals['_ACCOUNTINFORESPONSE']._serialized_start=646 + _globals['_ACCOUNTINFORESPONSE']._serialized_end=754 + _globals['_ACCOUNTINFOSERVICE']._serialized_start=756 + _globals['_ACCOUNTINFOSERVICE']._serialized_end=865 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/account_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/account_pb2_grpc.py new file mode 100644 index 0000000..81847fd --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/account_pb2_grpc.py @@ -0,0 +1,101 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import account_pb2 as account__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in account_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class AccountInfoServiceStub(object): + """Service definition for Account Information + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetAccountInfo = channel.unary_unary( + '/metatrader.v1.AccountInfoService/GetAccountInfo', + request_serializer=account__pb2.AccountInfoRequest.SerializeToString, + response_deserializer=account__pb2.AccountInfoResponse.FromString, + _registered_method=True) + + +class AccountInfoServiceServicer(object): + """Service definition for Account Information + """ + + def GetAccountInfo(self, request, context): + """Get information about the current trading account + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_AccountInfoServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetAccountInfo': grpc.unary_unary_rpc_method_handler( + servicer.GetAccountInfo, + request_deserializer=account__pb2.AccountInfoRequest.FromString, + response_serializer=account__pb2.AccountInfoResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.AccountInfoService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.AccountInfoService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class AccountInfoService(object): + """Service definition for Account Information + """ + + @staticmethod + def GetAccountInfo(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.AccountInfoService/GetAccountInfo', + account__pb2.AccountInfoRequest.SerializeToString, + account__pb2.AccountInfoResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/common_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/common_pb2.py new file mode 100644 index 0000000..c4200e7 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/common_pb2.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: common.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'common.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x63ommon.proto\x12\rmetatrader.v1\"&\n\x05\x45rror\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\"\x15\n\x13GetLastErrorRequest\";\n\x14GetLastErrorResponse\x12#\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x14.metatrader.v1.Error\"\x07\n\x05\x45mpty\",\n\x0e\x43onnectRequest\x12\x11\n\x04path\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x07\n\x05_path\"0\n\nTimeFilter\x12\x11\n\tdate_from\x18\x01 \x01(\x03\x12\x0f\n\x07\x64\x61te_to\x18\x02 \x01(\x03\x32\x9e\x01\n\x11MetaTraderService\x12>\n\x07\x43onnect\x12\x1d.metatrader.v1.ConnectRequest\x1a\x14.metatrader.v1.Error\x12I\n\x0cGetLastError\x12\x14.metatrader.v1.Empty\x1a#.metatrader.v1.GetLastErrorResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'common_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_ERROR']._serialized_start=31 + _globals['_ERROR']._serialized_end=69 + _globals['_GETLASTERRORREQUEST']._serialized_start=71 + _globals['_GETLASTERRORREQUEST']._serialized_end=92 + _globals['_GETLASTERRORRESPONSE']._serialized_start=94 + _globals['_GETLASTERRORRESPONSE']._serialized_end=153 + _globals['_EMPTY']._serialized_start=155 + _globals['_EMPTY']._serialized_end=162 + _globals['_CONNECTREQUEST']._serialized_start=164 + _globals['_CONNECTREQUEST']._serialized_end=208 + _globals['_TIMEFILTER']._serialized_start=210 + _globals['_TIMEFILTER']._serialized_end=258 + _globals['_METATRADERSERVICE']._serialized_start=261 + _globals['_METATRADERSERVICE']._serialized_end=419 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/common_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/common_pb2_grpc.py new file mode 100644 index 0000000..b1c65cc --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/common_pb2_grpc.py @@ -0,0 +1,143 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import common_pb2 as common__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in common_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class MetaTraderServiceStub(object): + """Service definition + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Connect = channel.unary_unary( + '/metatrader.v1.MetaTraderService/Connect', + request_serializer=common__pb2.ConnectRequest.SerializeToString, + response_deserializer=common__pb2.Error.FromString, + _registered_method=True) + self.GetLastError = channel.unary_unary( + '/metatrader.v1.MetaTraderService/GetLastError', + request_serializer=common__pb2.Empty.SerializeToString, + response_deserializer=common__pb2.GetLastErrorResponse.FromString, + _registered_method=True) + + +class MetaTraderServiceServicer(object): + """Service definition + """ + + def Connect(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetLastError(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_MetaTraderServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Connect': grpc.unary_unary_rpc_method_handler( + servicer.Connect, + request_deserializer=common__pb2.ConnectRequest.FromString, + response_serializer=common__pb2.Error.SerializeToString, + ), + 'GetLastError': grpc.unary_unary_rpc_method_handler( + servicer.GetLastError, + request_deserializer=common__pb2.Empty.FromString, + response_serializer=common__pb2.GetLastErrorResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.MetaTraderService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.MetaTraderService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class MetaTraderService(object): + """Service definition + """ + + @staticmethod + def Connect(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MetaTraderService/Connect', + common__pb2.ConnectRequest.SerializeToString, + common__pb2.Error.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetLastError(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MetaTraderService/GetLastError', + common__pb2.Empty.SerializeToString, + common__pb2.GetLastErrorResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/deal_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/deal_pb2.py new file mode 100644 index 0000000..ec188d9 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/deal_pb2.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: deal.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'deal.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ndeal.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\"\x8e\x01\n\x0c\x44\x65\x61lsRequest\x12\x30\n\x0btime_filter\x18\x01 \x01(\x0b\x32\x19.metatrader.v1.TimeFilterH\x00\x12\x10\n\x06ticket\x18\x02 \x01(\x04H\x00\x12\x12\n\x08position\x18\x03 \x01(\x04H\x00\x12\x12\n\x05group\x18\x04 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06\x66ilterB\x08\n\x06_group\"g\n\rDealsResponse\x12\"\n\x05\x64\x65\x61ls\x18\x01 \x03(\x0b\x32\x13.metatrader.v1.Deal\x12(\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.ErrorH\x00\x88\x01\x01\x42\x08\n\x06_error\"\xaa\x02\n\x04\x44\x65\x61l\x12\x0e\n\x06ticket\x18\x01 \x01(\x04\x12\r\n\x05order\x18\x02 \x01(\x04\x12\x0c\n\x04time\x18\x03 \x01(\x03\x12\x10\n\x08time_msc\x18\x04 \x01(\x03\x12\x0c\n\x04type\x18\x05 \x01(\x05\x12\r\n\x05\x65ntry\x18\x06 \x01(\x05\x12\r\n\x05magic\x18\x07 \x01(\r\x12\x13\n\x0bposition_id\x18\x08 \x01(\x04\x12\x0e\n\x06reason\x18\t \x01(\x05\x12\x0e\n\x06volume\x18\n \x01(\x01\x12\r\n\x05price\x18\x0b \x01(\x01\x12\x12\n\ncommission\x18\x0c \x01(\x01\x12\x0c\n\x04swap\x18\r \x01(\x01\x12\x0e\n\x06profit\x18\x0e \x01(\x01\x12\x0b\n\x03\x66\x65\x65\x18\x0f \x01(\x01\x12\x0e\n\x06symbol\x18\x10 \x01(\t\x12\x0f\n\x07\x63omment\x18\x11 \x01(\t\x12\x13\n\x0b\x65xternal_id\x18\x12 \x01(\t2\\\n\x13TradeHistoryService\x12\x45\n\x08GetDeals\x12\x1b.metatrader.v1.DealsRequest\x1a\x1c.metatrader.v1.DealsResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'deal_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_DEALSREQUEST']._serialized_start=44 + _globals['_DEALSREQUEST']._serialized_end=186 + _globals['_DEALSRESPONSE']._serialized_start=188 + _globals['_DEALSRESPONSE']._serialized_end=291 + _globals['_DEAL']._serialized_start=294 + _globals['_DEAL']._serialized_end=592 + _globals['_TRADEHISTORYSERVICE']._serialized_start=594 + _globals['_TRADEHISTORYSERVICE']._serialized_end=686 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/deal_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/deal_pb2_grpc.py new file mode 100644 index 0000000..97efb6e --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/deal_pb2_grpc.py @@ -0,0 +1,101 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import deal_pb2 as deal__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in deal_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class TradeHistoryServiceStub(object): + """Service definition for dealing with trade history + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetDeals = channel.unary_unary( + '/metatrader.v1.TradeHistoryService/GetDeals', + request_serializer=deal__pb2.DealsRequest.SerializeToString, + response_deserializer=deal__pb2.DealsResponse.FromString, + _registered_method=True) + + +class TradeHistoryServiceServicer(object): + """Service definition for dealing with trade history + """ + + def GetDeals(self, request, context): + """Get deals from trading history within specified parameters + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_TradeHistoryServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetDeals': grpc.unary_unary_rpc_method_handler( + servicer.GetDeals, + request_deserializer=deal__pb2.DealsRequest.FromString, + response_serializer=deal__pb2.DealsResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.TradeHistoryService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.TradeHistoryService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class TradeHistoryService(object): + """Service definition for dealing with trade history + """ + + @staticmethod + def GetDeals(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.TradeHistoryService/GetDeals', + deal__pb2.DealsRequest.SerializeToString, + deal__pb2.DealsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/history_orders_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/history_orders_pb2.py new file mode 100644 index 0000000..f988c98 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/history_orders_pb2.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: history_orders.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'history_orders.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14history_orders.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x96\x01\n\x14HistoryOrdersRequest\x12\x30\n\x0btime_filter\x18\x01 \x01(\x0b\x32\x19.metatrader.v1.TimeFilterH\x00\x12\x10\n\x06ticket\x18\x02 \x01(\x04H\x00\x12\x12\n\x08position\x18\x03 \x01(\x04H\x00\x12\x12\n\x05group\x18\x04 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06\x66ilterB\x08\n\x06_group\"?\n\x19HistoryOrdersTotalRequest\x12\x11\n\tdate_from\x18\x01 \x01(\x03\x12\x0f\n\x07\x64\x61te_to\x18\x02 \x01(\x03\"_\n\x1aHistoryOrdersTotalResponse\x12\r\n\x05total\x18\x01 \x01(\x05\x12(\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.ErrorH\x00\x88\x01\x01\x42\x08\n\x06_error\"x\n\x15HistoryOrdersResponse\x12+\n\x06orders\x18\x01 \x03(\x0b\x32\x1b.metatrader.v1.HistoryOrder\x12(\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.ErrorH\x00\x88\x01\x01\x42\x08\n\x06_error\"\x9d\x04\n\x0cHistoryOrder\x12\x0e\n\x06ticket\x18\x01 \x01(\x04\x12.\n\ntime_setup\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x16\n\x0etime_setup_msc\x18\x03 \x01(\x03\x12-\n\ttime_done\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x15\n\rtime_done_msc\x18\x05 \x01(\x03\x12\x33\n\x0ftime_expiration\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04type\x18\x07 \x01(\x05\x12\x11\n\ttype_time\x18\x08 \x01(\x05\x12\x14\n\x0ctype_filling\x18\t \x01(\x05\x12\r\n\x05state\x18\n \x01(\x05\x12\r\n\x05magic\x18\x0b \x01(\r\x12\x13\n\x0bposition_id\x18\x0c \x01(\x04\x12\x16\n\x0evolume_initial\x18\r \x01(\x01\x12\x16\n\x0evolume_current\x18\x0e \x01(\x01\x12\x12\n\nprice_open\x18\x0f \x01(\x01\x12\x11\n\tstop_loss\x18\x10 \x01(\x01\x12\x13\n\x0btake_profit\x18\x11 \x01(\x01\x12\x15\n\rprice_current\x18\x12 \x01(\x01\x12\x17\n\x0fprice_stoplimit\x18\x13 \x01(\x01\x12\x0e\n\x06symbol\x18\x14 \x01(\t\x12\x0f\n\x07\x63omment\x18\x15 \x01(\t\x12\x13\n\x0b\x65xternal_id\x18\x16 \x01(\t2\xe3\x01\n\x14HistoryOrdersService\x12]\n\x10GetHistoryOrders\x12#.metatrader.v1.HistoryOrdersRequest\x1a$.metatrader.v1.HistoryOrdersResponse\x12l\n\x15GetHistoryOrdersTotal\x12(.metatrader.v1.HistoryOrdersTotalRequest\x1a).metatrader.v1.HistoryOrdersTotalResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'history_orders_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_HISTORYORDERSREQUEST']._serialized_start=87 + _globals['_HISTORYORDERSREQUEST']._serialized_end=237 + _globals['_HISTORYORDERSTOTALREQUEST']._serialized_start=239 + _globals['_HISTORYORDERSTOTALREQUEST']._serialized_end=302 + _globals['_HISTORYORDERSTOTALRESPONSE']._serialized_start=304 + _globals['_HISTORYORDERSTOTALRESPONSE']._serialized_end=399 + _globals['_HISTORYORDERSRESPONSE']._serialized_start=401 + _globals['_HISTORYORDERSRESPONSE']._serialized_end=521 + _globals['_HISTORYORDER']._serialized_start=524 + _globals['_HISTORYORDER']._serialized_end=1065 + _globals['_HISTORYORDERSSERVICE']._serialized_start=1068 + _globals['_HISTORYORDERSSERVICE']._serialized_end=1295 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/history_orders_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/history_orders_pb2_grpc.py new file mode 100644 index 0000000..472f069 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/history_orders_pb2_grpc.py @@ -0,0 +1,145 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import history_orders_pb2 as history__orders__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in history_orders_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class HistoryOrdersServiceStub(object): + """Service definition for historical orders + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetHistoryOrders = channel.unary_unary( + '/metatrader.v1.HistoryOrdersService/GetHistoryOrders', + request_serializer=history__orders__pb2.HistoryOrdersRequest.SerializeToString, + response_deserializer=history__orders__pb2.HistoryOrdersResponse.FromString, + _registered_method=True) + self.GetHistoryOrdersTotal = channel.unary_unary( + '/metatrader.v1.HistoryOrdersService/GetHistoryOrdersTotal', + request_serializer=history__orders__pb2.HistoryOrdersTotalRequest.SerializeToString, + response_deserializer=history__orders__pb2.HistoryOrdersTotalResponse.FromString, + _registered_method=True) + + +class HistoryOrdersServiceServicer(object): + """Service definition for historical orders + """ + + def GetHistoryOrders(self, request, context): + """Get orders from trading history within specified parameters + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetHistoryOrdersTotal(self, request, context): + """Get total number of orders in history for a specified period + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_HistoryOrdersServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetHistoryOrders': grpc.unary_unary_rpc_method_handler( + servicer.GetHistoryOrders, + request_deserializer=history__orders__pb2.HistoryOrdersRequest.FromString, + response_serializer=history__orders__pb2.HistoryOrdersResponse.SerializeToString, + ), + 'GetHistoryOrdersTotal': grpc.unary_unary_rpc_method_handler( + servicer.GetHistoryOrdersTotal, + request_deserializer=history__orders__pb2.HistoryOrdersTotalRequest.FromString, + response_serializer=history__orders__pb2.HistoryOrdersTotalResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.HistoryOrdersService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.HistoryOrdersService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class HistoryOrdersService(object): + """Service definition for historical orders + """ + + @staticmethod + def GetHistoryOrders(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.HistoryOrdersService/GetHistoryOrders', + history__orders__pb2.HistoryOrdersRequest.SerializeToString, + history__orders__pb2.HistoryOrdersResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetHistoryOrdersTotal(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.HistoryOrdersService/GetHistoryOrdersTotal', + history__orders__pb2.HistoryOrdersTotalRequest.SerializeToString, + history__orders__pb2.HistoryOrdersTotalResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/initialize_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/initialize_pb2.py new file mode 100644 index 0000000..6c8d72b --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/initialize_pb2.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: initialize.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'initialize.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10initialize.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\"?\n\x0cLoginRequest\x12\r\n\x05login\x18\x01 \x01(\x03\x12\x10\n\x08password\x18\x02 \x01(\t\x12\x0e\n\x06server\x18\x03 \x01(\t\"E\n\rLoginResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"\x11\n\x0fShutdownRequest\"H\n\x10ShutdownResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"\x10\n\x0eVersionRequest\"G\n\x0fVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2\xf7\x01\n\x11InitializeService\x12\x44\n\x05Login\x12\x1b.metatrader.v1.LoginRequest\x1a\x1c.metatrader.v1.LoginResponse\"\x00\x12M\n\x08Shutdown\x12\x1e.metatrader.v1.ShutdownRequest\x1a\x1f.metatrader.v1.ShutdownResponse\"\x00\x12M\n\nGetVersion\x12\x1d.metatrader.v1.VersionRequest\x1a\x1e.metatrader.v1.VersionResponse\"\x00\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'initialize_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_LOGINREQUEST']._serialized_start=49 + _globals['_LOGINREQUEST']._serialized_end=112 + _globals['_LOGINRESPONSE']._serialized_start=114 + _globals['_LOGINRESPONSE']._serialized_end=183 + _globals['_SHUTDOWNREQUEST']._serialized_start=185 + _globals['_SHUTDOWNREQUEST']._serialized_end=202 + _globals['_SHUTDOWNRESPONSE']._serialized_start=204 + _globals['_SHUTDOWNRESPONSE']._serialized_end=276 + _globals['_VERSIONREQUEST']._serialized_start=278 + _globals['_VERSIONREQUEST']._serialized_end=294 + _globals['_VERSIONRESPONSE']._serialized_start=296 + _globals['_VERSIONRESPONSE']._serialized_end=367 + _globals['_INITIALIZESERVICE']._serialized_start=370 + _globals['_INITIALIZESERVICE']._serialized_end=617 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/initialize_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/initialize_pb2_grpc.py new file mode 100644 index 0000000..f89104c --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/initialize_pb2_grpc.py @@ -0,0 +1,186 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import initialize_pb2 as initialize__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in initialize_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class InitializeServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Login = channel.unary_unary( + '/metatrader.v1.InitializeService/Login', + request_serializer=initialize__pb2.LoginRequest.SerializeToString, + response_deserializer=initialize__pb2.LoginResponse.FromString, + _registered_method=True) + self.Shutdown = channel.unary_unary( + '/metatrader.v1.InitializeService/Shutdown', + request_serializer=initialize__pb2.ShutdownRequest.SerializeToString, + response_deserializer=initialize__pb2.ShutdownResponse.FromString, + _registered_method=True) + self.GetVersion = channel.unary_unary( + '/metatrader.v1.InitializeService/GetVersion', + request_serializer=initialize__pb2.VersionRequest.SerializeToString, + response_deserializer=initialize__pb2.VersionResponse.FromString, + _registered_method=True) + + +class InitializeServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def Login(self, request, context): + """Connect to the specified trading account + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Shutdown(self, request, context): + """Shut down connection to the MetaTrader 5 terminal + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetVersion(self, request, context): + """Get the MetaTrader 5 terminal version + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_InitializeServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Login': grpc.unary_unary_rpc_method_handler( + servicer.Login, + request_deserializer=initialize__pb2.LoginRequest.FromString, + response_serializer=initialize__pb2.LoginResponse.SerializeToString, + ), + 'Shutdown': grpc.unary_unary_rpc_method_handler( + servicer.Shutdown, + request_deserializer=initialize__pb2.ShutdownRequest.FromString, + response_serializer=initialize__pb2.ShutdownResponse.SerializeToString, + ), + 'GetVersion': grpc.unary_unary_rpc_method_handler( + servicer.GetVersion, + request_deserializer=initialize__pb2.VersionRequest.FromString, + response_serializer=initialize__pb2.VersionResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.InitializeService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.InitializeService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class InitializeService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def Login(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.InitializeService/Login', + initialize__pb2.LoginRequest.SerializeToString, + initialize__pb2.LoginResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def Shutdown(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.InitializeService/Shutdown', + initialize__pb2.ShutdownRequest.SerializeToString, + initialize__pb2.ShutdownResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetVersion(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.InitializeService/GetVersion', + initialize__pb2.VersionRequest.SerializeToString, + initialize__pb2.VersionResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/market_book_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/market_book_pb2.py new file mode 100644 index 0000000..f34aed6 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/market_book_pb2.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: market_book.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'market_book.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11market_book.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\"7\n\x08\x42ookInfo\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\r\n\x05price\x18\x02 \x01(\x01\x12\x0e\n\x06volume\x18\x03 \x01(\x01\"&\n\x14MarketBookAddRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\"M\n\x15MarketBookAddResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"&\n\x14MarketBookGetRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\"c\n\x15MarketBookGetResponse\x12%\n\x04\x62ook\x18\x01 \x03(\x0b\x32\x17.metatrader.v1.BookInfo\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"*\n\x18MarketBookReleaseRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\"Q\n\x19MarketBookReleaseResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error*\x82\x01\n\tBOOK_TYPE\x12\x19\n\x15\x42OOK_TYPE_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x42OOK_TYPE_SELL\x10\x01\x12\x11\n\rBOOK_TYPE_BUY\x10\x02\x12\x19\n\x15\x42OOK_TYPE_SELL_MARKET\x10\x03\x12\x18\n\x14\x42OOK_TYPE_BUY_MARKET\x10\x04\x32\xb3\x02\n\x11MarketBookService\x12Z\n\rAddMarketBook\x12#.metatrader.v1.MarketBookAddRequest\x1a$.metatrader.v1.MarketBookAddResponse\x12Z\n\rGetMarketBook\x12#.metatrader.v1.MarketBookGetRequest\x1a$.metatrader.v1.MarketBookGetResponse\x12\x66\n\x11ReleaseMarketBook\x12\'.metatrader.v1.MarketBookReleaseRequest\x1a(.metatrader.v1.MarketBookReleaseResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'market_book_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_BOOK_TYPE']._serialized_start=495 + _globals['_BOOK_TYPE']._serialized_end=625 + _globals['_BOOKINFO']._serialized_start=50 + _globals['_BOOKINFO']._serialized_end=105 + _globals['_MARKETBOOKADDREQUEST']._serialized_start=107 + _globals['_MARKETBOOKADDREQUEST']._serialized_end=145 + _globals['_MARKETBOOKADDRESPONSE']._serialized_start=147 + _globals['_MARKETBOOKADDRESPONSE']._serialized_end=224 + _globals['_MARKETBOOKGETREQUEST']._serialized_start=226 + _globals['_MARKETBOOKGETREQUEST']._serialized_end=264 + _globals['_MARKETBOOKGETRESPONSE']._serialized_start=266 + _globals['_MARKETBOOKGETRESPONSE']._serialized_end=365 + _globals['_MARKETBOOKRELEASEREQUEST']._serialized_start=367 + _globals['_MARKETBOOKRELEASEREQUEST']._serialized_end=409 + _globals['_MARKETBOOKRELEASERESPONSE']._serialized_start=411 + _globals['_MARKETBOOKRELEASERESPONSE']._serialized_end=492 + _globals['_MARKETBOOKSERVICE']._serialized_start=628 + _globals['_MARKETBOOKSERVICE']._serialized_end=935 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/market_book_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/market_book_pb2_grpc.py new file mode 100644 index 0000000..47fd689 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/market_book_pb2_grpc.py @@ -0,0 +1,189 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import market_book_pb2 as market__book__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in market_book_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class MarketBookServiceStub(object): + """Service definition for Market Book operations + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.AddMarketBook = channel.unary_unary( + '/metatrader.v1.MarketBookService/AddMarketBook', + request_serializer=market__book__pb2.MarketBookAddRequest.SerializeToString, + response_deserializer=market__book__pb2.MarketBookAddResponse.FromString, + _registered_method=True) + self.GetMarketBook = channel.unary_unary( + '/metatrader.v1.MarketBookService/GetMarketBook', + request_serializer=market__book__pb2.MarketBookGetRequest.SerializeToString, + response_deserializer=market__book__pb2.MarketBookGetResponse.FromString, + _registered_method=True) + self.ReleaseMarketBook = channel.unary_unary( + '/metatrader.v1.MarketBookService/ReleaseMarketBook', + request_serializer=market__book__pb2.MarketBookReleaseRequest.SerializeToString, + response_deserializer=market__book__pb2.MarketBookReleaseResponse.FromString, + _registered_method=True) + + +class MarketBookServiceServicer(object): + """Service definition for Market Book operations + """ + + def AddMarketBook(self, request, context): + """Subscribe to market depth updates + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetMarketBook(self, request, context): + """Get current market depth data + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ReleaseMarketBook(self, request, context): + """Unsubscribe from market depth updates + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_MarketBookServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'AddMarketBook': grpc.unary_unary_rpc_method_handler( + servicer.AddMarketBook, + request_deserializer=market__book__pb2.MarketBookAddRequest.FromString, + response_serializer=market__book__pb2.MarketBookAddResponse.SerializeToString, + ), + 'GetMarketBook': grpc.unary_unary_rpc_method_handler( + servicer.GetMarketBook, + request_deserializer=market__book__pb2.MarketBookGetRequest.FromString, + response_serializer=market__book__pb2.MarketBookGetResponse.SerializeToString, + ), + 'ReleaseMarketBook': grpc.unary_unary_rpc_method_handler( + servicer.ReleaseMarketBook, + request_deserializer=market__book__pb2.MarketBookReleaseRequest.FromString, + response_serializer=market__book__pb2.MarketBookReleaseResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.MarketBookService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.MarketBookService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class MarketBookService(object): + """Service definition for Market Book operations + """ + + @staticmethod + def AddMarketBook(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MarketBookService/AddMarketBook', + market__book__pb2.MarketBookAddRequest.SerializeToString, + market__book__pb2.MarketBookAddResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetMarketBook(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MarketBookService/GetMarketBook', + market__book__pb2.MarketBookGetRequest.SerializeToString, + market__book__pb2.MarketBookGetResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ReleaseMarketBook(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MarketBookService/ReleaseMarketBook', + market__book__pb2.MarketBookReleaseRequest.SerializeToString, + market__book__pb2.MarketBookReleaseResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/market_data_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/market_data_pb2.py new file mode 100644 index 0000000..72ff839 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/market_data_pb2.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: market_data.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'market_data.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11market_data.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xa2\x01\n\x04Rate\x12(\n\x04time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04open\x18\x02 \x01(\x01\x12\x0c\n\x04high\x18\x03 \x01(\x01\x12\x0b\n\x03low\x18\x04 \x01(\x01\x12\r\n\x05\x63lose\x18\x05 \x01(\x01\x12\x13\n\x0btick_volume\x18\x06 \x01(\x03\x12\x0e\n\x06spread\x18\x07 \x01(\x05\x12\x13\n\x0breal_volume\x18\x08 \x01(\x03\"\x9e\x01\n\x04Tick\x12(\n\x04time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0b\n\x03\x62id\x18\x02 \x01(\x01\x12\x0b\n\x03\x61sk\x18\x03 \x01(\x01\x12\x0c\n\x04last\x18\x04 \x01(\x01\x12\x0e\n\x06volume\x18\x05 \x01(\x04\x12\x10\n\x08time_msc\x18\x06 \x01(\x03\x12\r\n\x05\x66lags\x18\x07 \x01(\r\x12\x13\n\x0bvolume_real\x18\x08 \x01(\x01\"w\n\x14\x43opyRatesFromRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\x12\x11\n\ttimeframe\x18\x02 \x01(\x05\x12-\n\tdate_from\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\r\n\x05\x63ount\x18\x04 \x01(\x05\"`\n\x15\x43opyRatesFromResponse\x12\"\n\x05rates\x18\x01 \x03(\x0b\x32\x13.metatrader.v1.Rate\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"^\n\x17\x43opyRatesFromPosRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\x12\x11\n\ttimeframe\x18\x02 \x01(\x05\x12\x11\n\tstart_pos\x18\x03 \x01(\x05\x12\r\n\x05\x63ount\x18\x04 \x01(\x05\"c\n\x18\x43opyRatesFromPosResponse\x12\"\n\x05rates\x18\x01 \x03(\x0b\x32\x13.metatrader.v1.Rate\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"\x96\x01\n\x15\x43opyRatesRangeRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\x12\x11\n\ttimeframe\x18\x02 \x01(\x05\x12-\n\tdate_from\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12+\n\x07\x64\x61te_to\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"a\n\x16\x43opyRatesRangeResponse\x12\"\n\x05rates\x18\x01 \x03(\x0b\x32\x13.metatrader.v1.Rate\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"s\n\x14\x43opyTicksFromRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\x12-\n\tdate_from\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\r\n\x05\x63ount\x18\x03 \x01(\x05\x12\r\n\x05\x66lags\x18\x04 \x01(\x05\"`\n\x15\x43opyTicksFromResponse\x12\"\n\x05ticks\x18\x01 \x03(\x0b\x32\x13.metatrader.v1.Tick\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"\x92\x01\n\x15\x43opyTicksRangeRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\x12-\n\tdate_from\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12+\n\x07\x64\x61te_to\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\r\n\x05\x66lags\x18\x04 \x01(\x05\"a\n\x16\x43opyTicksRangeResponse\x12\"\n\x05ticks\x18\x01 \x03(\x0b\x32\x13.metatrader.v1.Tick\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error*\xbb\x03\n\tTIMEFRAME\x12\x19\n\x15TIMEFRAME_UNSPECIFIED\x10\x00\x12\x10\n\x0cTIMEFRAME_M1\x10\x01\x12\x10\n\x0cTIMEFRAME_M2\x10\x02\x12\x10\n\x0cTIMEFRAME_M3\x10\x03\x12\x10\n\x0cTIMEFRAME_M4\x10\x04\x12\x10\n\x0cTIMEFRAME_M5\x10\x05\x12\x10\n\x0cTIMEFRAME_M6\x10\x06\x12\x11\n\rTIMEFRAME_M10\x10\n\x12\x11\n\rTIMEFRAME_M12\x10\x0c\x12\x11\n\rTIMEFRAME_M15\x10\x0f\x12\x11\n\rTIMEFRAME_M20\x10\x14\x12\x11\n\rTIMEFRAME_M30\x10\x1e\x12\x12\n\x0cTIMEFRAME_H1\x10\x81\x80\x01\x12\x12\n\x0cTIMEFRAME_H2\x10\x82\x80\x01\x12\x12\n\x0cTIMEFRAME_H3\x10\x83\x80\x01\x12\x12\n\x0cTIMEFRAME_H4\x10\x84\x80\x01\x12\x12\n\x0cTIMEFRAME_H6\x10\x86\x80\x01\x12\x12\n\x0cTIMEFRAME_H8\x10\x88\x80\x01\x12\x13\n\rTIMEFRAME_H12\x10\x8c\x80\x01\x12\x12\n\x0cTIMEFRAME_D1\x10\x98\x80\x01\x12\x12\n\x0cTIMEFRAME_W1\x10\x81\x80\x02\x12\x13\n\rTIMEFRAME_MN1\x10\x81\x80\x03*g\n\nCOPY_TICKS\x12\x1a\n\x16\x43OPY_TICKS_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x43OPY_TICKS_ALL\x10\x01\x12\x13\n\x0f\x43OPY_TICKS_INFO\x10\x02\x12\x14\n\x10\x43OPY_TICKS_TRADE\x10\x04*\x9d\x01\n\tTICK_FLAG\x12\x19\n\x15TICK_FLAG_UNSPECIFIED\x10\x00\x12\x11\n\rTICK_FLAG_BID\x10\x02\x12\x11\n\rTICK_FLAG_ASK\x10\x04\x12\x12\n\x0eTICK_FLAG_LAST\x10\x08\x12\x14\n\x10TICK_FLAG_VOLUME\x10\x10\x12\x11\n\rTICK_FLAG_BUY\x10 \x12\x12\n\x0eTICK_FLAG_SELL\x10@2\xee\x03\n\x11MarketDataService\x12Z\n\rCopyRatesFrom\x12#.metatrader.v1.CopyRatesFromRequest\x1a$.metatrader.v1.CopyRatesFromResponse\x12\x63\n\x10\x43opyRatesFromPos\x12&.metatrader.v1.CopyRatesFromPosRequest\x1a\'.metatrader.v1.CopyRatesFromPosResponse\x12]\n\x0e\x43opyRatesRange\x12$.metatrader.v1.CopyRatesRangeRequest\x1a%.metatrader.v1.CopyRatesRangeResponse\x12Z\n\rCopyTicksFrom\x12#.metatrader.v1.CopyTicksFromRequest\x1a$.metatrader.v1.CopyTicksFromResponse\x12]\n\x0e\x43opyTicksRange\x12$.metatrader.v1.CopyTicksRangeRequest\x1a%.metatrader.v1.CopyTicksRangeResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'market_data_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_TIMEFRAME']._serialized_start=1541 + _globals['_TIMEFRAME']._serialized_end=1984 + _globals['_COPY_TICKS']._serialized_start=1986 + _globals['_COPY_TICKS']._serialized_end=2089 + _globals['_TICK_FLAG']._serialized_start=2092 + _globals['_TICK_FLAG']._serialized_end=2249 + _globals['_RATE']._serialized_start=84 + _globals['_RATE']._serialized_end=246 + _globals['_TICK']._serialized_start=249 + _globals['_TICK']._serialized_end=407 + _globals['_COPYRATESFROMREQUEST']._serialized_start=409 + _globals['_COPYRATESFROMREQUEST']._serialized_end=528 + _globals['_COPYRATESFROMRESPONSE']._serialized_start=530 + _globals['_COPYRATESFROMRESPONSE']._serialized_end=626 + _globals['_COPYRATESFROMPOSREQUEST']._serialized_start=628 + _globals['_COPYRATESFROMPOSREQUEST']._serialized_end=722 + _globals['_COPYRATESFROMPOSRESPONSE']._serialized_start=724 + _globals['_COPYRATESFROMPOSRESPONSE']._serialized_end=823 + _globals['_COPYRATESRANGEREQUEST']._serialized_start=826 + _globals['_COPYRATESRANGEREQUEST']._serialized_end=976 + _globals['_COPYRATESRANGERESPONSE']._serialized_start=978 + _globals['_COPYRATESRANGERESPONSE']._serialized_end=1075 + _globals['_COPYTICKSFROMREQUEST']._serialized_start=1077 + _globals['_COPYTICKSFROMREQUEST']._serialized_end=1192 + _globals['_COPYTICKSFROMRESPONSE']._serialized_start=1194 + _globals['_COPYTICKSFROMRESPONSE']._serialized_end=1290 + _globals['_COPYTICKSRANGEREQUEST']._serialized_start=1293 + _globals['_COPYTICKSRANGEREQUEST']._serialized_end=1439 + _globals['_COPYTICKSRANGERESPONSE']._serialized_start=1441 + _globals['_COPYTICKSRANGERESPONSE']._serialized_end=1538 + _globals['_MARKETDATASERVICE']._serialized_start=2252 + _globals['_MARKETDATASERVICE']._serialized_end=2746 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/market_data_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/market_data_pb2_grpc.py new file mode 100644 index 0000000..8bf8abe --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/market_data_pb2_grpc.py @@ -0,0 +1,277 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import market_data_pb2 as market__data__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in market_data_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class MarketDataServiceStub(object): + """Service definition for Market Data + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.CopyRatesFrom = channel.unary_unary( + '/metatrader.v1.MarketDataService/CopyRatesFrom', + request_serializer=market__data__pb2.CopyRatesFromRequest.SerializeToString, + response_deserializer=market__data__pb2.CopyRatesFromResponse.FromString, + _registered_method=True) + self.CopyRatesFromPos = channel.unary_unary( + '/metatrader.v1.MarketDataService/CopyRatesFromPos', + request_serializer=market__data__pb2.CopyRatesFromPosRequest.SerializeToString, + response_deserializer=market__data__pb2.CopyRatesFromPosResponse.FromString, + _registered_method=True) + self.CopyRatesRange = channel.unary_unary( + '/metatrader.v1.MarketDataService/CopyRatesRange', + request_serializer=market__data__pb2.CopyRatesRangeRequest.SerializeToString, + response_deserializer=market__data__pb2.CopyRatesRangeResponse.FromString, + _registered_method=True) + self.CopyTicksFrom = channel.unary_unary( + '/metatrader.v1.MarketDataService/CopyTicksFrom', + request_serializer=market__data__pb2.CopyTicksFromRequest.SerializeToString, + response_deserializer=market__data__pb2.CopyTicksFromResponse.FromString, + _registered_method=True) + self.CopyTicksRange = channel.unary_unary( + '/metatrader.v1.MarketDataService/CopyTicksRange', + request_serializer=market__data__pb2.CopyTicksRangeRequest.SerializeToString, + response_deserializer=market__data__pb2.CopyTicksRangeResponse.FromString, + _registered_method=True) + + +class MarketDataServiceServicer(object): + """Service definition for Market Data + """ + + def CopyRatesFrom(self, request, context): + """Get bars from specified date + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CopyRatesFromPos(self, request, context): + """Get bars from specified position + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CopyRatesRange(self, request, context): + """Get bars for specified date range + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CopyTicksFrom(self, request, context): + """Get ticks from specified date + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CopyTicksRange(self, request, context): + """Get ticks for specified date range + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_MarketDataServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'CopyRatesFrom': grpc.unary_unary_rpc_method_handler( + servicer.CopyRatesFrom, + request_deserializer=market__data__pb2.CopyRatesFromRequest.FromString, + response_serializer=market__data__pb2.CopyRatesFromResponse.SerializeToString, + ), + 'CopyRatesFromPos': grpc.unary_unary_rpc_method_handler( + servicer.CopyRatesFromPos, + request_deserializer=market__data__pb2.CopyRatesFromPosRequest.FromString, + response_serializer=market__data__pb2.CopyRatesFromPosResponse.SerializeToString, + ), + 'CopyRatesRange': grpc.unary_unary_rpc_method_handler( + servicer.CopyRatesRange, + request_deserializer=market__data__pb2.CopyRatesRangeRequest.FromString, + response_serializer=market__data__pb2.CopyRatesRangeResponse.SerializeToString, + ), + 'CopyTicksFrom': grpc.unary_unary_rpc_method_handler( + servicer.CopyTicksFrom, + request_deserializer=market__data__pb2.CopyTicksFromRequest.FromString, + response_serializer=market__data__pb2.CopyTicksFromResponse.SerializeToString, + ), + 'CopyTicksRange': grpc.unary_unary_rpc_method_handler( + servicer.CopyTicksRange, + request_deserializer=market__data__pb2.CopyTicksRangeRequest.FromString, + response_serializer=market__data__pb2.CopyTicksRangeResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.MarketDataService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.MarketDataService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class MarketDataService(object): + """Service definition for Market Data + """ + + @staticmethod + def CopyRatesFrom(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MarketDataService/CopyRatesFrom', + market__data__pb2.CopyRatesFromRequest.SerializeToString, + market__data__pb2.CopyRatesFromResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CopyRatesFromPos(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MarketDataService/CopyRatesFromPos', + market__data__pb2.CopyRatesFromPosRequest.SerializeToString, + market__data__pb2.CopyRatesFromPosResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CopyRatesRange(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MarketDataService/CopyRatesRange', + market__data__pb2.CopyRatesRangeRequest.SerializeToString, + market__data__pb2.CopyRatesRangeResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CopyTicksFrom(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MarketDataService/CopyTicksFrom', + market__data__pb2.CopyTicksFromRequest.SerializeToString, + market__data__pb2.CopyTicksFromResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CopyTicksRange(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.MarketDataService/CopyTicksRange', + market__data__pb2.CopyTicksRangeRequest.SerializeToString, + market__data__pb2.CopyTicksRangeResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/order_calc_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/order_calc_pb2.py new file mode 100644 index 0000000..ce548b2 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/order_calc_pb2.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: order_calc.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'order_calc.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10order_calc.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\"W\n\x16OrderCalcMarginRequest\x12\x0e\n\x06\x61\x63tion\x18\x01 \x01(\x05\x12\x0e\n\x06symbol\x18\x02 \x01(\t\x12\x0e\n\x06volume\x18\x03 \x01(\x01\x12\r\n\x05price\x18\x04 \x01(\x01\"N\n\x17OrderCalcMarginResponse\x12\x0e\n\x06margin\x18\x01 \x01(\x01\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"q\n\x16OrderCalcProfitRequest\x12\x0e\n\x06\x61\x63tion\x18\x01 \x01(\x05\x12\x0e\n\x06symbol\x18\x02 \x01(\t\x12\x0e\n\x06volume\x18\x03 \x01(\x01\x12\x12\n\nprice_open\x18\x04 \x01(\x01\x12\x13\n\x0bprice_close\x18\x05 \x01(\x01\"N\n\x17OrderCalcProfitResponse\x12\x0e\n\x06profit\x18\x01 \x01(\x01\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2\xcc\x01\n\x10OrderCalcService\x12[\n\nCalcMargin\x12%.metatrader.v1.OrderCalcMarginRequest\x1a&.metatrader.v1.OrderCalcMarginResponse\x12[\n\nCalcProfit\x12%.metatrader.v1.OrderCalcProfitRequest\x1a&.metatrader.v1.OrderCalcProfitResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'order_calc_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_ORDERCALCMARGINREQUEST']._serialized_start=49 + _globals['_ORDERCALCMARGINREQUEST']._serialized_end=136 + _globals['_ORDERCALCMARGINRESPONSE']._serialized_start=138 + _globals['_ORDERCALCMARGINRESPONSE']._serialized_end=216 + _globals['_ORDERCALCPROFITREQUEST']._serialized_start=218 + _globals['_ORDERCALCPROFITREQUEST']._serialized_end=331 + _globals['_ORDERCALCPROFITRESPONSE']._serialized_start=333 + _globals['_ORDERCALCPROFITRESPONSE']._serialized_end=411 + _globals['_ORDERCALCSERVICE']._serialized_start=414 + _globals['_ORDERCALCSERVICE']._serialized_end=618 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/order_calc_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/order_calc_pb2_grpc.py new file mode 100644 index 0000000..3050a43 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/order_calc_pb2_grpc.py @@ -0,0 +1,145 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import order_calc_pb2 as order__calc__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in order_calc_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class OrderCalcServiceStub(object): + """Service definition for Order Calculations + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.CalcMargin = channel.unary_unary( + '/metatrader.v1.OrderCalcService/CalcMargin', + request_serializer=order__calc__pb2.OrderCalcMarginRequest.SerializeToString, + response_deserializer=order__calc__pb2.OrderCalcMarginResponse.FromString, + _registered_method=True) + self.CalcProfit = channel.unary_unary( + '/metatrader.v1.OrderCalcService/CalcProfit', + request_serializer=order__calc__pb2.OrderCalcProfitRequest.SerializeToString, + response_deserializer=order__calc__pb2.OrderCalcProfitResponse.FromString, + _registered_method=True) + + +class OrderCalcServiceServicer(object): + """Service definition for Order Calculations + """ + + def CalcMargin(self, request, context): + """Calculate margin required for a trading operation + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CalcProfit(self, request, context): + """Calculate potential profit for a trading operation + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_OrderCalcServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'CalcMargin': grpc.unary_unary_rpc_method_handler( + servicer.CalcMargin, + request_deserializer=order__calc__pb2.OrderCalcMarginRequest.FromString, + response_serializer=order__calc__pb2.OrderCalcMarginResponse.SerializeToString, + ), + 'CalcProfit': grpc.unary_unary_rpc_method_handler( + servicer.CalcProfit, + request_deserializer=order__calc__pb2.OrderCalcProfitRequest.FromString, + response_serializer=order__calc__pb2.OrderCalcProfitResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.OrderCalcService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.OrderCalcService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class OrderCalcService(object): + """Service definition for Order Calculations + """ + + @staticmethod + def CalcMargin(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.OrderCalcService/CalcMargin', + order__calc__pb2.OrderCalcMarginRequest.SerializeToString, + order__calc__pb2.OrderCalcMarginResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CalcProfit(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.OrderCalcService/CalcProfit', + order__calc__pb2.OrderCalcProfitRequest.SerializeToString, + order__calc__pb2.OrderCalcProfitResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/order_check_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/order_check_pb2.py new file mode 100644 index 0000000..953d9cd --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/order_check_pb2.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: order_check.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'order_check.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 +from . import trade_pb2 as trade__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11order_check.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\x1a\x0btrade.proto\"\xce\x01\n\x10OrderCheckResult\x12\x0f\n\x07retcode\x18\x01 \x01(\x05\x12\x0f\n\x07\x62\x61lance\x18\x02 \x01(\x01\x12\x0e\n\x06\x65quity\x18\x03 \x01(\x01\x12\x0e\n\x06profit\x18\x04 \x01(\x01\x12\x0e\n\x06margin\x18\x05 \x01(\x01\x12\x13\n\x0bmargin_free\x18\x06 \x01(\x01\x12\x14\n\x0cmargin_level\x18\x07 \x01(\x01\x12\x0f\n\x07\x63omment\x18\x08 \x01(\t\x12,\n\x07request\x18\t \x01(\x0b\x32\x1b.metatrader.v1.TradeRequest\"G\n\x11OrderCheckRequest\x12\x32\n\rtrade_request\x18\x01 \x01(\x0b\x32\x1b.metatrader.v1.TradeRequest\"p\n\x12OrderCheckResponse\x12\x35\n\x0c\x63heck_result\x18\x01 \x01(\x0b\x32\x1f.metatrader.v1.OrderCheckResult\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2f\n\x11OrderCheckService\x12Q\n\nCheckOrder\x12 .metatrader.v1.OrderCheckRequest\x1a!.metatrader.v1.OrderCheckResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'order_check_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_ORDERCHECKRESULT']._serialized_start=64 + _globals['_ORDERCHECKRESULT']._serialized_end=270 + _globals['_ORDERCHECKREQUEST']._serialized_start=272 + _globals['_ORDERCHECKREQUEST']._serialized_end=343 + _globals['_ORDERCHECKRESPONSE']._serialized_start=345 + _globals['_ORDERCHECKRESPONSE']._serialized_end=457 + _globals['_ORDERCHECKSERVICE']._serialized_start=459 + _globals['_ORDERCHECKSERVICE']._serialized_end=561 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/order_check_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/order_check_pb2_grpc.py new file mode 100644 index 0000000..ac71138 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/order_check_pb2_grpc.py @@ -0,0 +1,101 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import order_check_pb2 as order__check__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in order_check_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class OrderCheckServiceStub(object): + """Service definition for Order Checking + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.CheckOrder = channel.unary_unary( + '/metatrader.v1.OrderCheckService/CheckOrder', + request_serializer=order__check__pb2.OrderCheckRequest.SerializeToString, + response_deserializer=order__check__pb2.OrderCheckResponse.FromString, + _registered_method=True) + + +class OrderCheckServiceServicer(object): + """Service definition for Order Checking + """ + + def CheckOrder(self, request, context): + """Check if an order can be executed + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_OrderCheckServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'CheckOrder': grpc.unary_unary_rpc_method_handler( + servicer.CheckOrder, + request_deserializer=order__check__pb2.OrderCheckRequest.FromString, + response_serializer=order__check__pb2.OrderCheckResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.OrderCheckService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.OrderCheckService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class OrderCheckService(object): + """Service definition for Order Checking + """ + + @staticmethod + def CheckOrder(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.OrderCheckService/CheckOrder', + order__check__pb2.OrderCheckRequest.SerializeToString, + order__check__pb2.OrderCheckResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/order_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/order_pb2.py new file mode 100644 index 0000000..61e5835 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/order_pb2.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: order.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'order.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0border.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"p\n\x10OrdersGetRequest\x12\x13\n\x06symbol\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x12\n\x05group\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06ticket\x18\x03 \x01(\x03H\x02\x88\x01\x01\x42\t\n\x07_symbolB\x08\n\x06_groupB\t\n\x07_ticket\"\xd0\x03\n\x05Order\x12\x0e\n\x06ticket\x18\x01 \x01(\x03\x12.\n\ntime_setup\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x16\n\x0etime_setup_msc\x18\x03 \x01(\x03\x12-\n\ttime_done\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x15\n\rtime_done_msc\x18\x05 \x01(\x03\x12\x33\n\x0ftime_expiration\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04type\x18\x07 \x01(\x05\x12\x11\n\ttype_time\x18\x08 \x01(\x05\x12\x14\n\x0ctype_filling\x18\t \x01(\x05\x12\r\n\x05state\x18\n \x01(\x05\x12\r\n\x05magic\x18\x0b \x01(\x05\x12\x16\n\x0evolume_current\x18\x0c \x01(\x01\x12\x12\n\nprice_open\x18\r \x01(\x01\x12\x11\n\tstop_loss\x18\x0e \x01(\x01\x12\x13\n\x0btake_profit\x18\x0f \x01(\x01\x12\x15\n\rprice_current\x18\x10 \x01(\x01\x12\x0e\n\x06symbol\x18\x11 \x01(\t\x12\x0f\n\x07\x63omment\x18\x12 \x01(\t\x12\x13\n\x0b\x65xternal_id\x18\x13 \x01(\t\"^\n\x11OrdersGetResponse\x12$\n\x06orders\x18\x01 \x03(\x0b\x32\x14.metatrader.v1.Order\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"\x14\n\x12OrdersTotalRequest\"I\n\x13OrdersTotalResponse\x12\r\n\x05total\x18\x01 \x01(\x05\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2\xb8\x01\n\rOrdersService\x12N\n\tGetOrders\x12\x1f.metatrader.v1.OrdersGetRequest\x1a .metatrader.v1.OrdersGetResponse\x12W\n\x0eGetOrdersTotal\x12!.metatrader.v1.OrdersTotalRequest\x1a\".metatrader.v1.OrdersTotalResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'order_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_ORDERSGETREQUEST']._serialized_start=77 + _globals['_ORDERSGETREQUEST']._serialized_end=189 + _globals['_ORDER']._serialized_start=192 + _globals['_ORDER']._serialized_end=656 + _globals['_ORDERSGETRESPONSE']._serialized_start=658 + _globals['_ORDERSGETRESPONSE']._serialized_end=752 + _globals['_ORDERSTOTALREQUEST']._serialized_start=754 + _globals['_ORDERSTOTALREQUEST']._serialized_end=774 + _globals['_ORDERSTOTALRESPONSE']._serialized_start=776 + _globals['_ORDERSTOTALRESPONSE']._serialized_end=849 + _globals['_ORDERSSERVICE']._serialized_start=852 + _globals['_ORDERSSERVICE']._serialized_end=1036 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/order_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/order_pb2_grpc.py new file mode 100644 index 0000000..052ddcb --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/order_pb2_grpc.py @@ -0,0 +1,145 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import order_pb2 as order__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in order_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class OrdersServiceStub(object): + """Service definition for Orders + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetOrders = channel.unary_unary( + '/metatrader.v1.OrdersService/GetOrders', + request_serializer=order__pb2.OrdersGetRequest.SerializeToString, + response_deserializer=order__pb2.OrdersGetResponse.FromString, + _registered_method=True) + self.GetOrdersTotal = channel.unary_unary( + '/metatrader.v1.OrdersService/GetOrdersTotal', + request_serializer=order__pb2.OrdersTotalRequest.SerializeToString, + response_deserializer=order__pb2.OrdersTotalResponse.FromString, + _registered_method=True) + + +class OrdersServiceServicer(object): + """Service definition for Orders + """ + + def GetOrders(self, request, context): + """Get active orders with optional filtering + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetOrdersTotal(self, request, context): + """Get total number of active orders + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_OrdersServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetOrders': grpc.unary_unary_rpc_method_handler( + servicer.GetOrders, + request_deserializer=order__pb2.OrdersGetRequest.FromString, + response_serializer=order__pb2.OrdersGetResponse.SerializeToString, + ), + 'GetOrdersTotal': grpc.unary_unary_rpc_method_handler( + servicer.GetOrdersTotal, + request_deserializer=order__pb2.OrdersTotalRequest.FromString, + response_serializer=order__pb2.OrdersTotalResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.OrdersService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.OrdersService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class OrdersService(object): + """Service definition for Orders + """ + + @staticmethod + def GetOrders(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.OrdersService/GetOrders', + order__pb2.OrdersGetRequest.SerializeToString, + order__pb2.OrdersGetResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetOrdersTotal(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.OrdersService/GetOrdersTotal', + order__pb2.OrdersTotalRequest.SerializeToString, + order__pb2.OrdersTotalResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/position_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/position_pb2.py new file mode 100644 index 0000000..55e3c42 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/position_pb2.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: position.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'position.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0eposition.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"s\n\x13PositionsGetRequest\x12\x13\n\x06symbol\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x12\n\x05group\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06ticket\x18\x03 \x01(\x03H\x02\x88\x01\x01\x42\t\n\x07_symbolB\x08\n\x06_groupB\t\n\x07_ticket\"\xa7\x02\n\x08Position\x12\x0e\n\x06ticket\x18\x01 \x01(\x03\x12\x0e\n\x06symbol\x18\x02 \x01(\t\x12\x0c\n\x04type\x18\x03 \x01(\x05\x12\r\n\x05magic\x18\x04 \x01(\x05\x12\x12\n\nidentifier\x18\x05 \x01(\x03\x12\x0e\n\x06reason\x18\x06 \x01(\x05\x12\x0e\n\x06volume\x18\x07 \x01(\x01\x12\x12\n\nprice_open\x18\x08 \x01(\x01\x12\x11\n\tstop_loss\x18\t \x01(\x01\x12\x13\n\x0btake_profit\x18\n \x01(\x01\x12\x15\n\rprice_current\x18\x0b \x01(\x01\x12\x0c\n\x04swap\x18\x0c \x01(\x01\x12\x0e\n\x06profit\x18\r \x01(\x01\x12\x0f\n\x07\x63omment\x18\x0e \x01(\t\x12(\n\x04time\x18\x0f \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"g\n\x14PositionsGetResponse\x12*\n\tpositions\x18\x01 \x03(\x0b\x32\x17.metatrader.v1.Position\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"\x17\n\x15PositionsTotalRequest\"L\n\x16PositionsTotalResponse\x12\r\n\x05total\x18\x01 \x01(\x05\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2\xcd\x01\n\x10PositionsService\x12W\n\x0cGetPositions\x12\".metatrader.v1.PositionsGetRequest\x1a#.metatrader.v1.PositionsGetResponse\x12`\n\x11GetPositionsTotal\x12$.metatrader.v1.PositionsTotalRequest\x1a%.metatrader.v1.PositionsTotalResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'position_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_POSITIONSGETREQUEST']._serialized_start=80 + _globals['_POSITIONSGETREQUEST']._serialized_end=195 + _globals['_POSITION']._serialized_start=198 + _globals['_POSITION']._serialized_end=493 + _globals['_POSITIONSGETRESPONSE']._serialized_start=495 + _globals['_POSITIONSGETRESPONSE']._serialized_end=598 + _globals['_POSITIONSTOTALREQUEST']._serialized_start=600 + _globals['_POSITIONSTOTALREQUEST']._serialized_end=623 + _globals['_POSITIONSTOTALRESPONSE']._serialized_start=625 + _globals['_POSITIONSTOTALRESPONSE']._serialized_end=701 + _globals['_POSITIONSSERVICE']._serialized_start=704 + _globals['_POSITIONSSERVICE']._serialized_end=909 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/position_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/position_pb2_grpc.py new file mode 100644 index 0000000..7dbda70 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/position_pb2_grpc.py @@ -0,0 +1,145 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import position_pb2 as position__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in position_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class PositionsServiceStub(object): + """Service definition for Positions + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetPositions = channel.unary_unary( + '/metatrader.v1.PositionsService/GetPositions', + request_serializer=position__pb2.PositionsGetRequest.SerializeToString, + response_deserializer=position__pb2.PositionsGetResponse.FromString, + _registered_method=True) + self.GetPositionsTotal = channel.unary_unary( + '/metatrader.v1.PositionsService/GetPositionsTotal', + request_serializer=position__pb2.PositionsTotalRequest.SerializeToString, + response_deserializer=position__pb2.PositionsTotalResponse.FromString, + _registered_method=True) + + +class PositionsServiceServicer(object): + """Service definition for Positions + """ + + def GetPositions(self, request, context): + """Get open positions with optional filtering + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetPositionsTotal(self, request, context): + """Get total number of open positions + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_PositionsServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetPositions': grpc.unary_unary_rpc_method_handler( + servicer.GetPositions, + request_deserializer=position__pb2.PositionsGetRequest.FromString, + response_serializer=position__pb2.PositionsGetResponse.SerializeToString, + ), + 'GetPositionsTotal': grpc.unary_unary_rpc_method_handler( + servicer.GetPositionsTotal, + request_deserializer=position__pb2.PositionsTotalRequest.FromString, + response_serializer=position__pb2.PositionsTotalResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.PositionsService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.PositionsService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class PositionsService(object): + """Service definition for Positions + """ + + @staticmethod + def GetPositions(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.PositionsService/GetPositions', + position__pb2.PositionsGetRequest.SerializeToString, + position__pb2.PositionsGetResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetPositionsTotal(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.PositionsService/GetPositionsTotal', + position__pb2.PositionsTotalRequest.SerializeToString, + position__pb2.PositionsTotalResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/symbol_info_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/symbol_info_pb2.py new file mode 100644 index 0000000..a0af64d --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/symbol_info_pb2.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: symbol_info.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'symbol_info.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11symbol_info.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xd6\x11\n\nSymbolInfo\x12\x0e\n\x06\x63ustom\x18\x01 \x01(\x08\x12\x0e\n\x06select\x18\x02 \x01(\x08\x12\x0f\n\x07visible\x18\x03 \x01(\x08\x12\x14\n\x0cspread_float\x18\x04 \x01(\x08\x12\x1d\n\x15margin_hedged_use_leg\x18\x05 \x01(\x08\x12\x12\n\nchart_mode\x18\n \x01(\x05\x12\x15\n\rsession_deals\x18\x0b \x01(\x05\x12\x1a\n\x12session_buy_orders\x18\x0c \x01(\x05\x12\x1b\n\x13session_sell_orders\x18\r \x01(\x05\x12\x0e\n\x06volume\x18\x0e \x01(\x05\x12\x12\n\nvolumehigh\x18\x0f \x01(\x05\x12\x11\n\tvolumelow\x18\x10 \x01(\x05\x12\x0e\n\x06\x64igits\x18\x11 \x01(\x05\x12\x0e\n\x06spread\x18\x12 \x01(\x05\x12\x17\n\x0fticks_bookdepth\x18\x13 \x01(\x05\x12\x17\n\x0ftrade_calc_mode\x18\x14 \x01(\x05\x12\x12\n\ntrade_mode\x18\x15 \x01(\x05\x12\x19\n\x11trade_stops_level\x18\x16 \x01(\x05\x12\x1a\n\x12trade_freeze_level\x18\x17 \x01(\x05\x12\x15\n\rtrade_exemode\x18\x18 \x01(\x05\x12\x11\n\tswap_mode\x18\x19 \x01(\x05\x12\x1a\n\x12swap_rollover3days\x18\x1a \x01(\x05\x12\x17\n\x0f\x65xpiration_mode\x18\x1b \x01(\x05\x12\x14\n\x0c\x66illing_mode\x18\x1c \x01(\x05\x12\x12\n\norder_mode\x18\x1d \x01(\x05\x12\x16\n\x0eorder_gtc_mode\x18\x1e \x01(\x05\x12\x13\n\x0boption_mode\x18\x1f \x01(\x05\x12\x14\n\x0coption_right\x18 \x01(\x05\x12(\n\x04time\x18( \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nstart_time\x18) \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x33\n\x0f\x65xpiration_time\x18* \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0b\n\x03\x62id\x18\x32 \x01(\x01\x12\x0f\n\x07\x62idhigh\x18\x33 \x01(\x01\x12\x0e\n\x06\x62idlow\x18\x34 \x01(\x01\x12\x0b\n\x03\x61sk\x18\x35 \x01(\x01\x12\x0f\n\x07\x61skhigh\x18\x36 \x01(\x01\x12\x0e\n\x06\x61sklow\x18\x37 \x01(\x01\x12\x0c\n\x04last\x18\x38 \x01(\x01\x12\x10\n\x08lasthigh\x18\x39 \x01(\x01\x12\x0f\n\x07lastlow\x18: \x01(\x01\x12\x13\n\x0bvolume_real\x18; \x01(\x01\x12\x17\n\x0fvolumehigh_real\x18< \x01(\x01\x12\x16\n\x0evolumelow_real\x18= \x01(\x01\x12\x15\n\roption_strike\x18> \x01(\x01\x12\r\n\x05point\x18? \x01(\x01\x12\x18\n\x10trade_tick_value\x18@ \x01(\x01\x12\x1f\n\x17trade_tick_value_profit\x18\x41 \x01(\x01\x12\x1d\n\x15trade_tick_value_loss\x18\x42 \x01(\x01\x12\x17\n\x0ftrade_tick_size\x18\x43 \x01(\x01\x12\x1b\n\x13trade_contract_size\x18\x44 \x01(\x01\x12\x1e\n\x16trade_accrued_interest\x18\x45 \x01(\x01\x12\x18\n\x10trade_face_value\x18\x46 \x01(\x01\x12\x1c\n\x14trade_liquidity_rate\x18G \x01(\x01\x12\x12\n\nvolume_min\x18H \x01(\x01\x12\x12\n\nvolume_max\x18I \x01(\x01\x12\x13\n\x0bvolume_step\x18J \x01(\x01\x12\x14\n\x0cvolume_limit\x18K \x01(\x01\x12\x11\n\tswap_long\x18L \x01(\x01\x12\x12\n\nswap_short\x18M \x01(\x01\x12\x16\n\x0emargin_initial\x18N \x01(\x01\x12\x1a\n\x12margin_maintenance\x18O \x01(\x01\x12\x16\n\x0esession_volume\x18P \x01(\x01\x12\x18\n\x10session_turnover\x18Q \x01(\x01\x12\x18\n\x10session_interest\x18R \x01(\x01\x12!\n\x19session_buy_orders_volume\x18S \x01(\x01\x12\"\n\x1asession_sell_orders_volume\x18T \x01(\x01\x12\x14\n\x0csession_open\x18U \x01(\x01\x12\x15\n\rsession_close\x18V \x01(\x01\x12\x12\n\nsession_aw\x18W \x01(\x01\x12 \n\x18session_price_settlement\x18X \x01(\x01\x12\x1f\n\x17session_price_limit_min\x18Y \x01(\x01\x12\x1f\n\x17session_price_limit_max\x18Z \x01(\x01\x12\x15\n\rmargin_hedged\x18[ \x01(\x01\x12\x14\n\x0cprice_change\x18\\ \x01(\x01\x12\x18\n\x10price_volatility\x18] \x01(\x01\x12\x19\n\x11price_theoretical\x18^ \x01(\x01\x12\x1a\n\x12price_greeks_delta\x18_ \x01(\x01\x12\x1a\n\x12price_greeks_theta\x18` \x01(\x01\x12\x1a\n\x12price_greeks_gamma\x18\x61 \x01(\x01\x12\x19\n\x11price_greeks_vega\x18\x62 \x01(\x01\x12\x18\n\x10price_greeks_rho\x18\x63 \x01(\x01\x12\x1a\n\x12price_greeks_omega\x18\x64 \x01(\x01\x12\x19\n\x11price_sensitivity\x18\x65 \x01(\x01\x12\r\n\x05\x62\x61sis\x18n \x01(\t\x12\x10\n\x08\x63\x61tegory\x18o \x01(\t\x12\x15\n\rcurrency_base\x18p \x01(\t\x12\x17\n\x0f\x63urrency_profit\x18q \x01(\t\x12\x17\n\x0f\x63urrency_margin\x18r \x01(\t\x12\x0c\n\x04\x62\x61nk\x18s \x01(\t\x12\x13\n\x0b\x64\x65scription\x18t \x01(\t\x12\x10\n\x08\x65xchange\x18u \x01(\t\x12\x0f\n\x07\x66ormula\x18v \x01(\t\x12\x0c\n\x04isin\x18w \x01(\t\x12\x0c\n\x04name\x18x \x01(\t\x12\x0c\n\x04page\x18y \x01(\t\x12\x0c\n\x04path\x18z \x01(\t\"#\n\x11SymbolInfoRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\"i\n\x12SymbolInfoResponse\x12.\n\x0bsymbol_info\x18\x01 \x01(\x0b\x32\x19.metatrader.v1.SymbolInfo\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2i\n\x11SymbolInfoService\x12T\n\rGetSymbolInfo\x12 .metatrader.v1.SymbolInfoRequest\x1a!.metatrader.v1.SymbolInfoResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'symbol_info_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SYMBOLINFO']._serialized_start=84 + _globals['_SYMBOLINFO']._serialized_end=2346 + _globals['_SYMBOLINFOREQUEST']._serialized_start=2348 + _globals['_SYMBOLINFOREQUEST']._serialized_end=2383 + _globals['_SYMBOLINFORESPONSE']._serialized_start=2385 + _globals['_SYMBOLINFORESPONSE']._serialized_end=2490 + _globals['_SYMBOLINFOSERVICE']._serialized_start=2492 + _globals['_SYMBOLINFOSERVICE']._serialized_end=2597 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/symbol_info_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/symbol_info_pb2_grpc.py new file mode 100644 index 0000000..1a01456 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/symbol_info_pb2_grpc.py @@ -0,0 +1,101 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import symbol_info_pb2 as symbol__info__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in symbol_info_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class SymbolInfoServiceStub(object): + """Service definition for Symbol Information + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetSymbolInfo = channel.unary_unary( + '/metatrader.v1.SymbolInfoService/GetSymbolInfo', + request_serializer=symbol__info__pb2.SymbolInfoRequest.SerializeToString, + response_deserializer=symbol__info__pb2.SymbolInfoResponse.FromString, + _registered_method=True) + + +class SymbolInfoServiceServicer(object): + """Service definition for Symbol Information + """ + + def GetSymbolInfo(self, request, context): + """Get information about a specific financial instrument + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_SymbolInfoServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetSymbolInfo': grpc.unary_unary_rpc_method_handler( + servicer.GetSymbolInfo, + request_deserializer=symbol__info__pb2.SymbolInfoRequest.FromString, + response_serializer=symbol__info__pb2.SymbolInfoResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.SymbolInfoService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.SymbolInfoService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class SymbolInfoService(object): + """Service definition for Symbol Information + """ + + @staticmethod + def GetSymbolInfo(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.SymbolInfoService/GetSymbolInfo', + symbol__info__pb2.SymbolInfoRequest.SerializeToString, + symbol__info__pb2.SymbolInfoResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/symbol_info_tick_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/symbol_info_tick_pb2.py new file mode 100644 index 0000000..0df3841 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/symbol_info_tick_pb2.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: symbol_info_tick.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'symbol_info_tick.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16symbol_info_tick.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xa8\x01\n\x0eSymbolInfoTick\x12(\n\x04time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0b\n\x03\x62id\x18\x02 \x01(\x01\x12\x0b\n\x03\x61sk\x18\x03 \x01(\x01\x12\x0c\n\x04last\x18\x04 \x01(\x01\x12\x0e\n\x06volume\x18\x05 \x01(\x05\x12\x10\n\x08time_msc\x18\x06 \x01(\x03\x12\r\n\x05\x66lags\x18\x07 \x01(\x05\x12\x13\n\x0bvolume_real\x18\x08 \x01(\x01\"\'\n\x15SymbolInfoTickRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\"j\n\x16SymbolInfoTickResponse\x12+\n\x04tick\x18\x01 \x01(\x0b\x32\x1d.metatrader.v1.SymbolInfoTick\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2y\n\x15SymbolInfoTickService\x12`\n\x11GetSymbolInfoTick\x12$.metatrader.v1.SymbolInfoTickRequest\x1a%.metatrader.v1.SymbolInfoTickResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'symbol_info_tick_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SYMBOLINFOTICK']._serialized_start=89 + _globals['_SYMBOLINFOTICK']._serialized_end=257 + _globals['_SYMBOLINFOTICKREQUEST']._serialized_start=259 + _globals['_SYMBOLINFOTICKREQUEST']._serialized_end=298 + _globals['_SYMBOLINFOTICKRESPONSE']._serialized_start=300 + _globals['_SYMBOLINFOTICKRESPONSE']._serialized_end=406 + _globals['_SYMBOLINFOTICKSERVICE']._serialized_start=408 + _globals['_SYMBOLINFOTICKSERVICE']._serialized_end=529 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/symbol_info_tick_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/symbol_info_tick_pb2_grpc.py new file mode 100644 index 0000000..3421953 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/symbol_info_tick_pb2_grpc.py @@ -0,0 +1,101 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import symbol_info_tick_pb2 as symbol__info__tick__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in symbol_info_tick_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class SymbolInfoTickServiceStub(object): + """Service definition for Symbol Tick Information + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetSymbolInfoTick = channel.unary_unary( + '/metatrader.v1.SymbolInfoTickService/GetSymbolInfoTick', + request_serializer=symbol__info__tick__pb2.SymbolInfoTickRequest.SerializeToString, + response_deserializer=symbol__info__tick__pb2.SymbolInfoTickResponse.FromString, + _registered_method=True) + + +class SymbolInfoTickServiceServicer(object): + """Service definition for Symbol Tick Information + """ + + def GetSymbolInfoTick(self, request, context): + """Get the last tick for a specific financial instrument + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_SymbolInfoTickServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetSymbolInfoTick': grpc.unary_unary_rpc_method_handler( + servicer.GetSymbolInfoTick, + request_deserializer=symbol__info__tick__pb2.SymbolInfoTickRequest.FromString, + response_serializer=symbol__info__tick__pb2.SymbolInfoTickResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.SymbolInfoTickService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.SymbolInfoTickService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class SymbolInfoTickService(object): + """Service definition for Symbol Tick Information + """ + + @staticmethod + def GetSymbolInfoTick(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.SymbolInfoTickService/GetSymbolInfoTick', + symbol__info__tick__pb2.SymbolInfoTickRequest.SerializeToString, + symbol__info__tick__pb2.SymbolInfoTickResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/symbols_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/symbols_pb2.py new file mode 100644 index 0000000..f7f9e95 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/symbols_pb2.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: symbols.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'symbols.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rsymbols.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\"\x15\n\x13SymbolsTotalRequest\"J\n\x14SymbolsTotalResponse\x12\r\n\x05total\x18\x01 \x01(\x05\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"\"\n\x11SymbolsGetRequest\x12\r\n\x05group\x18\x01 \x01(\t\"J\n\x12SymbolsGetResponse\x12\x0f\n\x07symbols\x18\x01 \x03(\t\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error\"5\n\x13SymbolSelectRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\x12\x0e\n\x06\x65nable\x18\x02 \x01(\x08\"L\n\x14SymbolSelectResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2\x9e\x02\n\x0eSymbolsService\x12\\\n\x0fGetSymbolsTotal\x12\".metatrader.v1.SymbolsTotalRequest\x1a#.metatrader.v1.SymbolsTotalResponse\"\x00\x12S\n\nGetSymbols\x12 .metatrader.v1.SymbolsGetRequest\x1a!.metatrader.v1.SymbolsGetResponse\"\x00\x12Y\n\x0cSelectSymbol\x12\".metatrader.v1.SymbolSelectRequest\x1a#.metatrader.v1.SymbolSelectResponse\"\x00\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'symbols_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SYMBOLSTOTALREQUEST']._serialized_start=46 + _globals['_SYMBOLSTOTALREQUEST']._serialized_end=67 + _globals['_SYMBOLSTOTALRESPONSE']._serialized_start=69 + _globals['_SYMBOLSTOTALRESPONSE']._serialized_end=143 + _globals['_SYMBOLSGETREQUEST']._serialized_start=145 + _globals['_SYMBOLSGETREQUEST']._serialized_end=179 + _globals['_SYMBOLSGETRESPONSE']._serialized_start=181 + _globals['_SYMBOLSGETRESPONSE']._serialized_end=255 + _globals['_SYMBOLSELECTREQUEST']._serialized_start=257 + _globals['_SYMBOLSELECTREQUEST']._serialized_end=310 + _globals['_SYMBOLSELECTRESPONSE']._serialized_start=312 + _globals['_SYMBOLSELECTRESPONSE']._serialized_end=388 + _globals['_SYMBOLSSERVICE']._serialized_start=391 + _globals['_SYMBOLSSERVICE']._serialized_end=677 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/symbols_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/symbols_pb2_grpc.py new file mode 100644 index 0000000..90482eb --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/symbols_pb2_grpc.py @@ -0,0 +1,189 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import symbols_pb2 as symbols__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in symbols_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class SymbolsServiceStub(object): + """Service for working with symbols + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetSymbolsTotal = channel.unary_unary( + '/metatrader.v1.SymbolsService/GetSymbolsTotal', + request_serializer=symbols__pb2.SymbolsTotalRequest.SerializeToString, + response_deserializer=symbols__pb2.SymbolsTotalResponse.FromString, + _registered_method=True) + self.GetSymbols = channel.unary_unary( + '/metatrader.v1.SymbolsService/GetSymbols', + request_serializer=symbols__pb2.SymbolsGetRequest.SerializeToString, + response_deserializer=symbols__pb2.SymbolsGetResponse.FromString, + _registered_method=True) + self.SelectSymbol = channel.unary_unary( + '/metatrader.v1.SymbolsService/SelectSymbol', + request_serializer=symbols__pb2.SymbolSelectRequest.SerializeToString, + response_deserializer=symbols__pb2.SymbolSelectResponse.FromString, + _registered_method=True) + + +class SymbolsServiceServicer(object): + """Service for working with symbols + """ + + def GetSymbolsTotal(self, request, context): + """Get the number of all financial instruments + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetSymbols(self, request, context): + """Get all financial instruments + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def SelectSymbol(self, request, context): + """Select a symbol in the Market Watch window + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_SymbolsServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetSymbolsTotal': grpc.unary_unary_rpc_method_handler( + servicer.GetSymbolsTotal, + request_deserializer=symbols__pb2.SymbolsTotalRequest.FromString, + response_serializer=symbols__pb2.SymbolsTotalResponse.SerializeToString, + ), + 'GetSymbols': grpc.unary_unary_rpc_method_handler( + servicer.GetSymbols, + request_deserializer=symbols__pb2.SymbolsGetRequest.FromString, + response_serializer=symbols__pb2.SymbolsGetResponse.SerializeToString, + ), + 'SelectSymbol': grpc.unary_unary_rpc_method_handler( + servicer.SelectSymbol, + request_deserializer=symbols__pb2.SymbolSelectRequest.FromString, + response_serializer=symbols__pb2.SymbolSelectResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.SymbolsService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.SymbolsService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class SymbolsService(object): + """Service for working with symbols + """ + + @staticmethod + def GetSymbolsTotal(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.SymbolsService/GetSymbolsTotal', + symbols__pb2.SymbolsTotalRequest.SerializeToString, + symbols__pb2.SymbolsTotalResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetSymbols(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.SymbolsService/GetSymbols', + symbols__pb2.SymbolsGetRequest.SerializeToString, + symbols__pb2.SymbolsGetResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def SelectSymbol(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.SymbolsService/SelectSymbol', + symbols__pb2.SymbolSelectRequest.SerializeToString, + symbols__pb2.SymbolSelectResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/terminal_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/terminal_pb2.py new file mode 100644 index 0000000..6621e2c --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/terminal_pb2.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: terminal.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'terminal.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0eterminal.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\"\x15\n\x13TerminalInfoRequest\"\x8b\x04\n\x14TerminalInfoResponse\x12\x19\n\x11\x63ommunity_account\x18\x01 \x01(\x08\x12\x1c\n\x14\x63ommunity_connection\x18\x02 \x01(\x08\x12\x11\n\tconnected\x18\x03 \x01(\x08\x12\x14\n\x0c\x64lls_allowed\x18\x04 \x01(\x08\x12\x15\n\rtrade_allowed\x18\x05 \x01(\x08\x12\x19\n\x11tradeapi_disabled\x18\x06 \x01(\x08\x12\x15\n\remail_enabled\x18\x07 \x01(\x08\x12\x13\n\x0b\x66tp_enabled\x18\x08 \x01(\x08\x12\x1d\n\x15notifications_enabled\x18\t \x01(\x08\x12\x0c\n\x04mqid\x18\n \x01(\x08\x12\r\n\x05\x62uild\x18\x0b \x01(\x05\x12\x0f\n\x07maxbars\x18\x0c \x01(\x05\x12\x10\n\x08\x63odepage\x18\r \x01(\x05\x12\x11\n\tping_last\x18\x0e \x01(\x05\x12\x19\n\x11\x63ommunity_balance\x18\x0f \x01(\x02\x12\x16\n\x0eretransmission\x18\x10 \x01(\x02\x12\x0f\n\x07\x63ompany\x18\x11 \x01(\t\x12\x0c\n\x04name\x18\x12 \x01(\t\x12\x10\n\x08language\x18\x13 \x01(\t\x12\x0c\n\x04path\x18\x14 \x01(\t\x12\x11\n\tdata_path\x18\x15 \x01(\t\x12\x17\n\x0f\x63ommondata_path\x18\x16 \x01(\t\x12#\n\x05\x65rror\x18\x17 \x01(\x0b\x32\x14.metatrader.v1.Error2s\n\x13TerminalInfoService\x12\\\n\x0fGetTerminalInfo\x12\".metatrader.v1.TerminalInfoRequest\x1a#.metatrader.v1.TerminalInfoResponse\"\x00\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'terminal_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_TERMINALINFOREQUEST']._serialized_start=47 + _globals['_TERMINALINFOREQUEST']._serialized_end=68 + _globals['_TERMINALINFORESPONSE']._serialized_start=71 + _globals['_TERMINALINFORESPONSE']._serialized_end=594 + _globals['_TERMINALINFOSERVICE']._serialized_start=596 + _globals['_TERMINALINFOSERVICE']._serialized_end=711 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/terminal_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/terminal_pb2_grpc.py new file mode 100644 index 0000000..85289d9 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/terminal_pb2_grpc.py @@ -0,0 +1,101 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import terminal_pb2 as terminal__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in terminal_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class TerminalInfoServiceStub(object): + """Service for getting terminal information + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetTerminalInfo = channel.unary_unary( + '/metatrader.v1.TerminalInfoService/GetTerminalInfo', + request_serializer=terminal__pb2.TerminalInfoRequest.SerializeToString, + response_deserializer=terminal__pb2.TerminalInfoResponse.FromString, + _registered_method=True) + + +class TerminalInfoServiceServicer(object): + """Service for getting terminal information + """ + + def GetTerminalInfo(self, request, context): + """Get MetaTrader 5 terminal information + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_TerminalInfoServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetTerminalInfo': grpc.unary_unary_rpc_method_handler( + servicer.GetTerminalInfo, + request_deserializer=terminal__pb2.TerminalInfoRequest.FromString, + response_serializer=terminal__pb2.TerminalInfoResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.TerminalInfoService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.TerminalInfoService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class TerminalInfoService(object): + """Service for getting terminal information + """ + + @staticmethod + def GetTerminalInfo(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.TerminalInfoService/GetTerminalInfo', + terminal__pb2.TerminalInfoRequest.SerializeToString, + terminal__pb2.TerminalInfoResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/mt5_grpc_proto/trade_pb2.py b/mt5_grpc_proto/mt5_grpc_proto/trade_pb2.py new file mode 100644 index 0000000..60b8288 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/trade_pb2.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: trade.proto +# Protobuf Python Version: 5.28.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 28, + 1, + '', + 'trade.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import common_pb2 as common__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btrade.proto\x12\rmetatrader.v1\x1a\x0c\x63ommon.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xed\x03\n\x0cTradeRequest\x12\x0e\n\x06\x61\x63tion\x18\x01 \x01(\x05\x12\r\n\x05magic\x18\x02 \x01(\x05\x12\x12\n\x05order\x18\x03 \x01(\x03H\x00\x88\x01\x01\x12\x13\n\x06symbol\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x0e\n\x06volume\x18\x05 \x01(\x01\x12\x12\n\x05price\x18\x06 \x01(\x01H\x02\x88\x01\x01\x12\x16\n\tstoplimit\x18\x07 \x01(\x01H\x03\x88\x01\x01\x12\x0f\n\x02sl\x18\x08 \x01(\x01H\x04\x88\x01\x01\x12\x0f\n\x02tp\x18\t \x01(\x01H\x05\x88\x01\x01\x12\x11\n\tdeviation\x18\n \x01(\x05\x12\x0c\n\x04type\x18\x0b \x01(\x05\x12\x14\n\x0ctype_filling\x18\x0c \x01(\x05\x12\x11\n\ttype_time\x18\r \x01(\x05\x12\x33\n\nexpiration\x18\x0e \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x06\x88\x01\x01\x12\x14\n\x07\x63omment\x18\x0f \x01(\tH\x07\x88\x01\x01\x12\x15\n\x08position\x18\x10 \x01(\x03H\x08\x88\x01\x01\x12\x18\n\x0bposition_by\x18\x11 \x01(\x03H\t\x88\x01\x01\x42\x08\n\x06_orderB\t\n\x07_symbolB\x08\n\x06_priceB\x0c\n\n_stoplimitB\x05\n\x03_slB\x05\n\x03_tpB\r\n\x0b_expirationB\n\n\x08_commentB\x0b\n\t_positionB\x0e\n\x0c_position_by\"\xe1\x01\n\x0bTradeResult\x12\x0f\n\x07retcode\x18\x01 \x01(\x05\x12\x0c\n\x04\x64\x65\x61l\x18\x02 \x01(\x03\x12\r\n\x05order\x18\x03 \x01(\x03\x12\x0e\n\x06volume\x18\x04 \x01(\x01\x12\r\n\x05price\x18\x05 \x01(\x01\x12\x0b\n\x03\x62id\x18\x06 \x01(\x01\x12\x0b\n\x03\x61sk\x18\x07 \x01(\x01\x12\x0f\n\x07\x63omment\x18\x08 \x01(\t\x12\x12\n\nrequest_id\x18\t \x01(\x03\x12\x18\n\x10retcode_external\x18\n \x01(\x05\x12,\n\x07request\x18\x0b \x01(\x0b\x32\x1b.metatrader.v1.TradeRequest\"F\n\x10OrderSendRequest\x12\x32\n\rtrade_request\x18\x01 \x01(\x0b\x32\x1b.metatrader.v1.TradeRequest\"j\n\x11OrderSendResponse\x12\x30\n\x0ctrade_result\x18\x01 \x01(\x0b\x32\x1a.metatrader.v1.TradeResult\x12#\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x14.metatrader.v1.Error2b\n\x10OrderSendService\x12N\n\tSendOrder\x12\x1f.metatrader.v1.OrderSendRequest\x1a .metatrader.v1.OrderSendResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'trade_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_TRADEREQUEST']._serialized_start=78 + _globals['_TRADEREQUEST']._serialized_end=571 + _globals['_TRADERESULT']._serialized_start=574 + _globals['_TRADERESULT']._serialized_end=799 + _globals['_ORDERSENDREQUEST']._serialized_start=801 + _globals['_ORDERSENDREQUEST']._serialized_end=871 + _globals['_ORDERSENDRESPONSE']._serialized_start=873 + _globals['_ORDERSENDRESPONSE']._serialized_end=979 + _globals['_ORDERSENDSERVICE']._serialized_start=981 + _globals['_ORDERSENDSERVICE']._serialized_end=1079 +# @@protoc_insertion_point(module_scope) diff --git a/mt5_grpc_proto/mt5_grpc_proto/trade_pb2_grpc.py b/mt5_grpc_proto/mt5_grpc_proto/trade_pb2_grpc.py new file mode 100644 index 0000000..5b507a4 --- /dev/null +++ b/mt5_grpc_proto/mt5_grpc_proto/trade_pb2_grpc.py @@ -0,0 +1,101 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +from . import trade_pb2 as trade__pb2 + +GRPC_GENERATED_VERSION = '1.68.1' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in trade_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class OrderSendServiceStub(object): + """Service definition for Order Sending + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.SendOrder = channel.unary_unary( + '/metatrader.v1.OrderSendService/SendOrder', + request_serializer=trade__pb2.OrderSendRequest.SerializeToString, + response_deserializer=trade__pb2.OrderSendResponse.FromString, + _registered_method=True) + + +class OrderSendServiceServicer(object): + """Service definition for Order Sending + """ + + def SendOrder(self, request, context): + """Send a trading order + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_OrderSendServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'SendOrder': grpc.unary_unary_rpc_method_handler( + servicer.SendOrder, + request_deserializer=trade__pb2.OrderSendRequest.FromString, + response_serializer=trade__pb2.OrderSendResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'metatrader.v1.OrderSendService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('metatrader.v1.OrderSendService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class OrderSendService(object): + """Service definition for Order Sending + """ + + @staticmethod + def SendOrder(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/metatrader.v1.OrderSendService/SendOrder', + trade__pb2.OrderSendRequest.SerializeToString, + trade__pb2.OrderSendResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/mt5_grpc_proto/pyproject.toml b/mt5_grpc_proto/pyproject.toml new file mode 100644 index 0000000..1b68d94 --- /dev/null +++ b/mt5_grpc_proto/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/mt5_grpc_proto/requirements.txt b/mt5_grpc_proto/requirements.txt new file mode 100644 index 0000000..bad3b5f --- /dev/null +++ b/mt5_grpc_proto/requirements.txt @@ -0,0 +1,3 @@ +grpcio==1.68.1 +grpcio-tools==1.68.1 +protobuf==5.29.2 \ No newline at end of file diff --git a/mt5_grpc_proto/setup.py b/mt5_grpc_proto/setup.py new file mode 100644 index 0000000..c04b89e --- /dev/null +++ b/mt5_grpc_proto/setup.py @@ -0,0 +1,38 @@ +from setuptools import setup, find_packages + +setup( + name="mt5_grpc_proto", + version="0.1.0", + description="Protocol Buffers and gRPC service definitions for MetaTrader 5 RPC Server", + long_description=open("README.md").read(), + long_description_content_type="text/markdown", + author="starmel", + author_email="slava.kornienko16@gmail.com", + url="https://github.com/Starmel/Metatrader5-gRPC-server", + packages=find_packages(), + install_requires=[ + "grpcio>=1.68.1", + "grpcio-tools>=1.68.1", + "protobuf>=5.29.2", + ], + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Intended Audience :: Financial and Insurance Industry", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Topic :: Office/Business :: Financial :: Investment", + "Topic :: Software Development :: Libraries :: Python Modules", + ], + python_requires=">=3.8", + keywords="metatrader, mt5, trading, grpc, protobuf, api", + project_urls={ + "Documentation": "https://github.com/Starmel/Metatrader5-gRPC-server/tree/main/docs", + "Source": "https://github.com/Starmel/Metatrader5-gRPC-server", + "Tracker": "https://github.com/Starmel/Metatrader5-gRPC-server/issues", + }, +) diff --git a/mt5_grpc_server/Readme.md b/mt5_grpc_server/Readme.md new file mode 100644 index 0000000..ed4d9a7 --- /dev/null +++ b/mt5_grpc_server/Readme.md @@ -0,0 +1,56 @@ +# MT5 gRPC Server + +A high-performance gRPC server implementation for MetaTrader 5, enabling remote trading operations and market data access. + +## Overview +This module provides a gRPC server that interfaces with MetaTrader 5 terminal, allowing remote access to trading operations, market data, and account management through a standardized gRPC API. + +## Installation + +```bash +pip install mt5-grpc-server +``` + +## Features + +- **Account Operations** + - Account info retrieval + - Balance and equity monitoring + - Trading history access + +- **Trading Operations** + - Order placement and modification + - Position management + - Order validation and calculations + +- **Market Data** + - Real-time price data + - Symbol information + - Market depth (DOM) + + +## Usage + +### Starting the Server + +Example with secure connection: +```bash +mt5-grpc-server --host 127.0.0.1 --port 50052 --secure --cert-file server.crt --private-key-file server.key +``` + +Or without secure connection: +```bash +# Default port is 50051 and host is 0.0.0.0 +mt5-grpc-server +``` + + +### Command-line Options + +The server supports the following command-line options: + +- `--host HOST`: Host address to bind the server to (default: "0.0.0.0") +- `--port PORT`: Port number to listen on (default: 50051) +- `--secure`: Enable secure connection with SSL/TLS +- `--cert-file FILE`: Path to the SSL certificate file (required if --secure is used) +- `--private-key-file FILE`: Path to the private key file (required if --secure is used) diff --git a/mt5_grpc_server/mt5_grpc_server/__init__.py b/mt5_grpc_server/mt5_grpc_server/__init__.py new file mode 100644 index 0000000..c9e6e6a --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/__init__.py @@ -0,0 +1 @@ +from .imp import * \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/grpc_server.py b/mt5_grpc_server/mt5_grpc_server/grpc_server.py new file mode 100644 index 0000000..a1ffbe6 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/grpc_server.py @@ -0,0 +1,89 @@ +import argparse +from concurrent import futures +import grpc +from mt5_grpc_proto import * +from .imp import * + +def load_credentials(cert_file, private_key_file): + # Read the certificate and private key files + with open(cert_file, 'rb') as f: + certificate_chain = f.read() + with open(private_key_file, 'rb') as f: + private_key = f.read() + + # Create server credentials + server_credentials = grpc.ssl_server_credentials( + [(private_key, certificate_chain)] + ) + return server_credentials + + +def main(): + parser = argparse.ArgumentParser( + description="Start gRPC server" + ) + parser.add_argument( + "--host", + type=str, + default="0.0.0.0", + help="Host for gRPC server (default: 0.0.0.0)" + ) + parser.add_argument( + "--port", + type=int, + default=50051, + help="Port for gRPC server (default: 50051)" + ) + parser.add_argument( + "--secure", + action="store_true", + help="Use secure connection with SSL/TLS" + ) + parser.add_argument( + "--cert-file", + type=str, + help="Path to the SSL certificate file (required if --secure is used)" + ) + parser.add_argument( + "--private-key-file", + type=str, + help="Path to the private key file (required if --secure is used)" + ) + args = parser.parse_args() + + if args.secure and (not args.cert_file or not args.private_key_file): + parser.error("--cert-file and --private-key-file are required when using --secure") + + print(f"Starting gRPC server on {args.host}:{args.port} {'(secure)' if args.secure else '(insecure)'}") + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + + # Add all services to the server + account_pb2_grpc.add_AccountInfoServiceServicer_to_server(AccountInfoServiceImpl(), server) + common_pb2_grpc.add_MetaTraderServiceServicer_to_server(MetaTraderServiceImpl(), server) + symbol_info_tick_pb2_grpc.add_SymbolInfoTickServiceServicer_to_server(SymbolInfoTickServiceImpl(), server) + symbol_info_pb2_grpc.add_SymbolInfoServiceServicer_to_server(SymbolInfoServiceImpl(), server) + trade_pb2_grpc.add_OrderSendServiceServicer_to_server(OrderSendServiceImpl(), server) + order_calc_pb2_grpc.add_OrderCalcServiceServicer_to_server(OrderCalcServiceImpl(), server) + order_check_pb2_grpc.add_OrderCheckServiceServicer_to_server(OrderCheckServiceImpl(), server) + market_data_pb2_grpc.add_MarketDataServiceServicer_to_server(MarketDataServiceImpl(), server) + market_book_pb2_grpc.add_MarketBookServiceServicer_to_server(MarketBookServiceImpl(), server) + terminal_pb2_grpc.add_TerminalInfoServiceServicer_to_server(TerminalInfoServiceImpl(), server) + symbols_pb2_grpc.add_SymbolsServiceServicer_to_server(SymbolsServiceImpl(), server) + initialize_pb2_grpc.add_InitializeServiceServicer_to_server(InitializeServiceImpl(), server) + history_orders_pb2_grpc.add_HistoryOrdersServiceServicer_to_server(HistoryOrdersServiceImpl(), server) + deal_pb2_grpc.add_TradeHistoryServiceServicer_to_server(TradeHistoryServiceImpl(), server) + order_pb2_grpc.add_OrdersServiceServicer_to_server(OrdersServiceImpl(), server) + position_pb2_grpc.add_PositionsServiceServicer_to_server(PositionsServiceImpl(), server) + + # Add server port based on security option + if args.secure: + server_credentials = load_credentials(args.cert_file, args.private_key_file) + server.add_secure_port(f'{args.host}:{args.port}', server_credentials) + else: + server.add_insecure_port(f'{args.host}:{args.port}') + + server.start() + server.wait_for_termination() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/__init__.py b/mt5_grpc_server/mt5_grpc_server/imp/__init__.py new file mode 100644 index 0000000..a18cad6 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/__init__.py @@ -0,0 +1,16 @@ +from .account_service import * +from .deals_history import * +from .history_orders import * +from .initialize import * +from .market_book import * +from .market_data import * +from .metatrader import * +from .order import * +from .order_calc import * +from .order_check import * +from .positions import * +from .symbol_info import * +from .symbol_info_tick import * +from .symbols import * +from .terminal_info import * +from .trade import * \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/account_service.py b/mt5_grpc_server/mt5_grpc_server/imp/account_service.py new file mode 100644 index 0000000..98eef58 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/account_service.py @@ -0,0 +1,82 @@ +import MetaTrader5 as mt5 +from mt5_grpc_proto.account_pb2 import AccountInfo, AccountInfoResponse +from mt5_grpc_proto.account_pb2_grpc import AccountInfoServiceServicer + + +class AccountInfoServiceImpl(AccountInfoServiceServicer): + def GetAccountInfo(self, request, context): + """ + Implements the GetAccountInfo RPC method. + Returns account information from MetaTrader 5. + """ + # Initialize the response + response = AccountInfoResponse() + + # Check if MT5 is initialized + if not mt5.initialize(): + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = error_message + return response + + try: + # Get account info from MT5 + account_info = mt5.account_info() + + if account_info is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = error_message + return response + + # Create AccountInfo message and populate it with MT5 data + info = AccountInfo() + + # Integer properties + info.login = account_info.login + info.trade_mode = account_info.trade_mode + info.leverage = account_info.leverage + info.limit_orders = account_info.limit_orders + info.margin_so_mode = account_info.margin_so_mode + info.margin_mode = account_info.margin_mode + info.currency_digits = account_info.currency_digits + + # Boolean properties + info.trade_allowed = account_info.trade_allowed + info.trade_expert = account_info.trade_expert + info.fifo_close = account_info.fifo_close + + # Double properties + info.balance = account_info.balance + info.credit = account_info.credit + info.profit = account_info.profit + info.equity = account_info.equity + info.margin = account_info.margin + info.margin_free = account_info.margin_free + info.margin_level = account_info.margin_level + info.margin_so_call = account_info.margin_so_call + info.margin_so_so = account_info.margin_so_so + info.margin_initial = account_info.margin_initial + info.margin_maintenance = account_info.margin_maintenance + info.assets = account_info.assets + info.liabilities = account_info.liabilities + info.commission_blocked = account_info.commission_blocked + + # String properties + info.name = account_info.name + info.server = account_info.server + info.currency = account_info.currency + info.company = account_info.company + + # Set the account_info field in the response + response.account_info.CopyFrom(info) + + return response + + except Exception as e: + response.error.code = -1 # Generic error code for exceptions + response.error.message = str(e) + return response + + finally: + mt5.shutdown() \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/deals_history.py b/mt5_grpc_server/mt5_grpc_server/imp/deals_history.py new file mode 100644 index 0000000..106bc14 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/deals_history.py @@ -0,0 +1,120 @@ +import MetaTrader5 as mt5 +from typing import Optional, Tuple +from mt5_grpc_proto.deal_pb2 import ( + DealsRequest, + DealsResponse, + Deal +) +from mt5_grpc_proto.deal_pb2_grpc import TradeHistoryServiceServicer +from mt5_grpc_proto.common_pb2 import Error + + +class TradeHistoryServiceImpl(TradeHistoryServiceServicer): + def __init__(self): + self._initialized = False + + def _ensure_initialized(self) -> Tuple[bool, Optional[Error]]: + """Initialize MT5 connection if not already initialized.""" + if not self._initialized: + if not mt5.initialize(): + error_code, error_message = mt5.last_error() + error = Error( + code=error_code, + message=f"MetaTrader5 initialization failed: {error_message}" + ) + return False, error + self._initialized = True + return True, None + + def _convert_deal_to_proto(self, mt5_deal) -> Deal: + """Convert MT5 deal object to protobuf Deal message. + + Args: + mt5_deal: Deal information from MT5 + + Returns: + Deal: Protobuf Deal message + """ + # Use the exact field names from the MT5 reference + return Deal( + ticket=mt5_deal.ticket, + order=mt5_deal.order, + time=int(mt5_deal.time), # MT5 returns Unix timestamp + time_msc=mt5_deal.time_msc, + type=mt5_deal.type, + entry=mt5_deal.entry, + magic=mt5_deal.magic, + position_id=mt5_deal.position_id, + reason=mt5_deal.reason, + volume=float(mt5_deal.volume), + price=float(mt5_deal.price), + commission=float(mt5_deal.commission), + swap=float(mt5_deal.swap), + profit=float(mt5_deal.profit), + fee=float(mt5_deal.fee), + symbol=mt5_deal.symbol, + comment=mt5_deal.comment, + external_id=mt5_deal.external_id + ) + + def GetDeals(self, request: DealsRequest, context) -> DealsResponse: + """Get deals from MT5 based on specified filters. + + According to MT5 reference, we can filter by: + 1. Time interval using date_from and date_to + 2. Symbol group using the group parameter + 3. Specific ticket + 4. Position ID + + Args: + request: DealsRequest containing filter criteria + context: gRPC context + + Returns: + DealsResponse containing matched deals or error + """ + response = DealsResponse() + + # Ensure MT5 is initialized + initialized, error = self._ensure_initialized() + if not initialized: + response.error.CopyFrom(error) + return response + + try: + # Handle different filter types according to MT5 reference + if request.HasField('time_filter'): + deals = mt5.history_deals_get( + request.time_filter.date_from, + request.time_filter.date_to, + group=request.group if request.HasField('group') else '*' + ) + elif request.HasField('ticket'): + # Use ticket parameter as documented + deals = mt5.history_deals_get(ticket=request.ticket) + elif request.HasField('position'): + # Use position parameter as documented + deals = mt5.history_deals_get(position=request.position) + else: + # If no filters specified, return error + response.error.code = -2 # RES_E_INVALID_PARAMS + response.error.message = "No valid filter criteria provided" + return response + + if deals is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = f"Failed to get deals: {error_message}" + return response + + # Convert MT5 deals to protobuf messages + for mt5_deal in deals: + deal_proto = self._convert_deal_to_proto(mt5_deal) + response.deals.append(deal_proto) + + return response + + except Exception as e: + response.error.code = -1 # RES_E_FAIL + response.error.message = f"Internal error processing deals: {str(e)}" + return response diff --git a/mt5_grpc_server/mt5_grpc_server/imp/history_orders.py b/mt5_grpc_server/mt5_grpc_server/imp/history_orders.py new file mode 100644 index 0000000..5a1255c --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/history_orders.py @@ -0,0 +1,161 @@ +import MetaTrader5 as mt5 +from typing import Optional, Tuple +from google.protobuf.timestamp_pb2 import Timestamp +from mt5_grpc_proto.history_orders_pb2 import ( + HistoryOrdersRequest, + HistoryOrdersResponse, + HistoryOrdersTotalRequest, + HistoryOrdersTotalResponse, + HistoryOrder +) +from mt5_grpc_proto.history_orders_pb2_grpc import HistoryOrdersServiceServicer +from mt5_grpc_proto.common_pb2 import Error + + +class HistoryOrdersServiceImpl(HistoryOrdersServiceServicer): + def __init__(self): + self._initialized = False + + def _ensure_initialized(self) -> Tuple[bool, Optional[Error]]: + """Initialize MT5 connection if not already initialized.""" + if not self._initialized: + if not mt5.initialize(): + error_code, error_message = mt5.last_error() + error = Error( + code=error_code, + message=f"MetaTrader5 initialization failed: {error_message}" + ) + return False, error + self._initialized = True + return True, None + + def _convert_timestamp(self, unix_timestamp: int) -> Timestamp: + """Convert Unix timestamp to protobuf Timestamp.""" + timestamp = Timestamp() + timestamp.FromSeconds(unix_timestamp) + return timestamp + + def _convert_order_to_proto(self, mt5_order) -> HistoryOrder: + """Convert MT5 order object to protobuf HistoryOrder message. + + Args: + mt5_order: Order information from MT5 + + Returns: + HistoryOrder: Protobuf HistoryOrder message + """ + return HistoryOrder( + ticket=mt5_order.ticket, + time_setup=self._convert_timestamp(int(mt5_order.time_setup)), + time_setup_msc=mt5_order.time_setup_msc, + time_done=self._convert_timestamp(int(mt5_order.time_done)), + time_done_msc=mt5_order.time_done_msc, + time_expiration=self._convert_timestamp(int(mt5_order.time_expiration)) if mt5_order.time_expiration else None, + type=mt5_order.type, + type_time=mt5_order.type_time, + type_filling=mt5_order.type_filling, + state=mt5_order.state, + magic=mt5_order.magic, + position_id=mt5_order.position_id, + volume_initial=float(mt5_order.volume_initial), + volume_current=float(mt5_order.volume_current), + price_open=float(mt5_order.price_open), + stop_loss=float(mt5_order.sl), + take_profit=float(mt5_order.tp), + price_current=float(mt5_order.price_current), + price_stoplimit=float(mt5_order.price_stoplimit), + symbol=mt5_order.symbol, + comment=mt5_order.comment, + external_id=mt5_order.external_id + ) + + def GetHistoryOrders(self, request: HistoryOrdersRequest, context) -> HistoryOrdersResponse: + """Get orders from trading history based on specified filters. + + Args: + request: HistoryOrdersRequest containing filter criteria + context: gRPC context + + Returns: + HistoryOrdersResponse containing matched orders or error + """ + response = HistoryOrdersResponse() + + # Ensure MT5 is initialized + initialized, error = self._ensure_initialized() + if not initialized: + response.error.CopyFrom(error) + return response + + try: + # Handle different filter types + if request.HasField('time_filter'): + orders = mt5.history_orders_get( + request.time_filter.date_from, + request.time_filter.date_to, + group=request.group if request.HasField('group') else '*' + ) + elif request.HasField('ticket'): + orders = mt5.history_orders_get(ticket=request.ticket) + elif request.HasField('position'): + orders = mt5.history_orders_get(position=request.position) + else: + response.error.code = -2 # RES_E_INVALID_PARAMS + response.error.message = "No valid filter criteria provided" + return response + + if orders is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = f"Failed to get orders: {error_message}" + return response + + # Convert MT5 orders to protobuf messages + for mt5_order in orders: + order_proto = self._convert_order_to_proto(mt5_order) + response.orders.append(order_proto) + + return response + + except Exception as e: + response.error.code = -1 # RES_E_FAIL + response.error.message = f"Internal error processing orders: {str(e)}" + return response + + def GetHistoryOrdersTotal(self, request: HistoryOrdersTotalRequest, context) -> HistoryOrdersTotalResponse: + """Get total number of orders in trading history within specified period. + + Args: + request: HistoryOrdersTotalRequest containing time period + context: gRPC context + + Returns: + HistoryOrdersTotalResponse containing total count or error + """ + response = HistoryOrdersTotalResponse() + + # Ensure MT5 is initialized + initialized, error = self._ensure_initialized() + if not initialized: + response.error.CopyFrom(error) + return response + + try: + total = mt5.history_orders_total( + request.date_from, + request.date_to + ) + + if total is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = f"Failed to get orders total: {error_message}" + return response + + response.total = total + return response + + except Exception as e: + response.error.code = -1 # RES_E_FAIL + response.error.message = f"Internal error getting orders total: {str(e)}" + return response \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/initialize.py b/mt5_grpc_server/mt5_grpc_server/imp/initialize.py new file mode 100644 index 0000000..ea741f6 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/initialize.py @@ -0,0 +1,59 @@ +import MetaTrader5 as mt5 +from mt5_grpc_proto.initialize_pb2 import ( + LoginResponse, ShutdownResponse, VersionResponse +) +from mt5_grpc_proto.initialize_pb2_grpc import InitializeServiceServicer +from mt5_grpc_proto.common_pb2 import Error + + +class InitializeServiceImpl(InitializeServiceServicer): + def Login(self, request, context): + """Connect to the specified trading account""" + success = mt5.login( + request.login, + request.password, + request.server + ) + + if not success: + error = mt5.last_error() + return LoginResponse( + success=False, + error=Error(code=error[0], message=error[1]) + ) + + return LoginResponse( + success=True, + error=Error(code=0, message="") + ) + + def Shutdown(self, request, context): + """Shut down connection to the MetaTrader 5 terminal""" + success = mt5.shutdown() + + if not success: + error = mt5.last_error() + return ShutdownResponse( + success=False, + error=Error(code=error[0], message=error[1]) + ) + + return ShutdownResponse( + success=True, + error=Error(code=0, message="") + ) + + def GetVersion(self, request, context): + """Get the MetaTrader 5 terminal version""" + version = mt5.version() + + if version is None: + error = mt5.last_error() + return VersionResponse( + error=Error(code=error[0], message=error[1]) + ) + + return VersionResponse( + version=f"{version[0]}.{version[1]}.{version[2]}", + error=Error(code=0, message="") + ) \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/market_book.py b/mt5_grpc_server/mt5_grpc_server/imp/market_book.py new file mode 100644 index 0000000..a91da91 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/market_book.py @@ -0,0 +1,64 @@ +import MetaTrader5 as mt5 +from mt5_grpc_proto.market_book_pb2 import ( + MarketBookAddResponse, MarketBookGetResponse, MarketBookReleaseResponse, + BookInfo +) +from mt5_grpc_proto.market_book_pb2_grpc import MarketBookServiceServicer +from mt5_grpc_proto.common_pb2 import Error + + +class MarketBookServiceImpl(MarketBookServiceServicer): + def _convert_to_book_info(self, mt5_book_info): + """Convert MT5 book info to protobuf BookInfo message""" + return BookInfo( + type=mt5_book_info.type, + price=mt5_book_info.price, + volume=mt5_book_info.volume + ) + + def AddMarketBook(self, request, context): + """Subscribe to market depth updates""" + success = mt5.market_book_add(request.symbol) + + if not success: + error = mt5.last_error() + return MarketBookAddResponse( + success=False, + error=Error(code=error[0], message=error[1]) + ) + + return MarketBookAddResponse( + success=True, + error=Error(code=0, message="") + ) + + def GetMarketBook(self, request, context): + """Get current market depth data""" + book = mt5.market_book_get(request.symbol) + + if book is None: + error = mt5.last_error() + return MarketBookGetResponse( + error=Error(code=error[0], message=error[1]) + ) + + return MarketBookGetResponse( + book=[self._convert_to_book_info(item) for item in book], + error=Error(code=0, message="") + ) + + def ReleaseMarketBook(self, request, context): + """Unsubscribe from market depth updates""" + success = mt5.market_book_release(request.symbol) + + if not success: + error = mt5.last_error() + return MarketBookReleaseResponse( + success=False, + error=Error(code=error[0], message=error[1]) + ) + + return MarketBookReleaseResponse( + success=True, + error=Error(code=0, message="") + ) \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/market_data.py b/mt5_grpc_server/mt5_grpc_server/imp/market_data.py new file mode 100644 index 0000000..6601267 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/market_data.py @@ -0,0 +1,159 @@ +import MetaTrader5 as mt5 +from datetime import datetime +import pytz + +from mt5_grpc_proto.market_data_pb2 import ( + CopyRatesFromResponse, CopyRatesFromPosResponse, CopyRatesRangeResponse, + CopyTicksFromResponse, CopyTicksRangeResponse, Rate, Tick +) +from mt5_grpc_proto.market_data_pb2_grpc import MarketDataServiceServicer +from mt5_grpc_proto.common_pb2 import Error +from google.protobuf.timestamp_pb2 import Timestamp + + +class MarketDataServiceImpl(MarketDataServiceServicer): + def _convert_to_rate(self, mt5_rate): + """Convert MT5 rate to protobuf Rate message""" + timestamp = Timestamp() + timestamp.FromSeconds(int(mt5_rate[0])) + + return Rate( + time=timestamp, + open=mt5_rate[1], + high=mt5_rate[2], + low=mt5_rate[3], + close=mt5_rate[4], + tick_volume=mt5_rate[5], + spread=mt5_rate[6], + real_volume=mt5_rate[7] + ) + + def _convert_to_tick(self, mt5_tick): + """Convert MT5 tick to protobuf Tick message""" + timestamp = Timestamp() + timestamp.FromSeconds(int(mt5_tick[0])) + + return Tick( + time=timestamp, + bid=mt5_tick[1], + ask=mt5_tick[2], + last=mt5_tick[3], + volume=mt5_tick[4], + time_msc=mt5_tick[5], + flags=mt5_tick[6], + volume_real=mt5_tick[7] + ) + + def CopyRatesFrom(self, request, context): + """Get bars from specified date""" + # Convert protobuf timestamp to datetime + date_from = datetime.fromtimestamp(request.date_from.seconds, tz=pytz.UTC) + + rates = mt5.copy_rates_from( + request.symbol, + request.timeframe, + date_from, + request.count + ) + + if rates is None: + error = mt5.last_error() + return CopyRatesFromResponse( + error=Error(code=error[0], message=error[1]) + ) + + return CopyRatesFromResponse( + rates=[self._convert_to_rate(rate) for rate in rates], + error=Error(code=0, message="") + ) + + def CopyRatesFromPos(self, request, context): + """Get bars from specified position""" + rates = mt5.copy_rates_from_pos( + request.symbol, + request.timeframe, + request.start_pos, + request.count + ) + + if rates is None: + error = mt5.last_error() + return CopyRatesFromPosResponse( + error=Error(code=error[0], message=error[1]) + ) + + return CopyRatesFromPosResponse( + rates=[self._convert_to_rate(rate) for rate in rates], + error=Error(code=0, message="") + ) + + def CopyRatesRange(self, request, context): + """Get bars for specified date range""" + # Convert protobuf timestamps to datetime + date_from = datetime.fromtimestamp(request.date_from.seconds, tz=pytz.UTC) + date_to = datetime.fromtimestamp(request.date_to.seconds, tz=pytz.UTC) + + rates = mt5.copy_rates_range( + request.symbol, + request.timeframe, + date_from, + date_to + ) + + if rates is None: + error = mt5.last_error() + return CopyRatesRangeResponse( + error=Error(code=error[0], message=error[1]) + ) + + return CopyRatesRangeResponse( + rates=[self._convert_to_rate(rate) for rate in rates], + error=Error(code=0, message="") + ) + + def CopyTicksFrom(self, request, context): + """Get ticks from specified date""" + # Convert protobuf timestamp to datetime + date_from = datetime.fromtimestamp(request.date_from.seconds, tz=pytz.UTC) + + ticks = mt5.copy_ticks_from( + request.symbol, + date_from, + request.count, + request.flags + ) + + if ticks is None: + error = mt5.last_error() + return CopyTicksFromResponse( + error=Error(code=error[0], message=error[1]) + ) + + return CopyTicksFromResponse( + ticks=[self._convert_to_tick(tick) for tick in ticks], + error=Error(code=0, message="") + ) + + def CopyTicksRange(self, request, context): + """Get ticks for specified date range""" + # Convert protobuf timestamps to datetime + date_from = datetime.fromtimestamp(request.date_from.seconds, tz=pytz.UTC) + date_to = datetime.fromtimestamp(request.date_to.seconds, tz=pytz.UTC) + + ticks = mt5.copy_ticks_range( + request.symbol, + date_from, + date_to, + request.flags + ) + + if ticks is None: + error = mt5.last_error() + return CopyTicksRangeResponse( + error=Error(code=error[0], message=error[1]) + ) + + return CopyTicksRangeResponse( + ticks=[self._convert_to_tick(tick) for tick in ticks], + error=Error(code=0, message="") + ) \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/metatrader.py b/mt5_grpc_server/mt5_grpc_server/imp/metatrader.py new file mode 100644 index 0000000..336334d --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/metatrader.py @@ -0,0 +1,61 @@ +import MetaTrader5 as mt5 +import grpc +import os + +from mt5_grpc_proto import common_pb2 +from mt5_grpc_proto.common_pb2 import Error, GetLastErrorResponse +from mt5_grpc_proto.common_pb2_grpc import MetaTraderServiceServicer + + +class MetaTraderServiceImpl(MetaTraderServiceServicer): + def GetLastError(self, request, context): + """Implementation of GetLastError RPC method""" + response = GetLastErrorResponse() + try: + # Get last error from MT5 + error_code, error_message = mt5.last_error() + + # Create error object + error = Error( + code=error_code, + message=error_message + ) + + # Set error in response + response.error.CopyFrom(error) + return response + + except Exception as e: + response.error.code = -1 # Generic error code for exceptions + response.error.message = str(e) + return response + + def Connect(self, request, context): + """Implementation of Connect RPC method""" + response = common_pb2.Empty() + try: + # If path is provided, set the MetaTrader5 path + if request.path: + # Validate the directory exists + if not os.path.isdir(request.path): + error_code, error_message = mt5.last_error() + context.abort(grpc.StatusCode.INVALID_ARGUMENT, f'Invalid directory path: {request.path}') + return None + + # Set the path for MetaTrader5 initialization + if not mt5.initialize(path=request.path): + error_code, error_message = mt5.last_error() + context.abort(grpc.StatusCode.INTERNAL, error_message) + return None + else: + # Initialize with default path + if not mt5.initialize(): + error_code, error_message = mt5.last_error() + context.abort(grpc.StatusCode.INTERNAL, error_message) + return None + + return response + + except Exception as e: + context.abort(grpc.StatusCode.INTERNAL, str(e)) + return None \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/order.py b/mt5_grpc_server/mt5_grpc_server/imp/order.py new file mode 100644 index 0000000..a569f31 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/order.py @@ -0,0 +1,193 @@ +import MetaTrader5 as mt5 +from datetime import datetime +from typing import Optional, Tuple, Union +from google.protobuf.timestamp_pb2 import Timestamp +from mt5_grpc_proto.common_pb2 import Error +from mt5_grpc_proto.order_pb2 import ( + OrdersGetRequest, + OrdersGetResponse, + OrdersTotalRequest, + OrdersTotalResponse, + Order +) +from mt5_grpc_proto.order_pb2_grpc import OrdersServiceServicer + + +class OrdersServiceImpl(OrdersServiceServicer): + """Implementation of Orders service for MetaTrader 5.""" + + def __init__(self): + self._initialized = False + + def _ensure_initialized(self) -> Tuple[bool, Optional[Error]]: + """Initialize MT5 connection if not already initialized. + + Returns: + Tuple[bool, Optional[Error]]: Success status and error if any + """ + if not self._initialized: + if not mt5.initialize(): + error_code, error_message = mt5.last_error() + error = Error( + code=error_code, + message=f"MetaTrader5 initialization failed: {error_message}" + ) + return False, error + self._initialized = True + return True, None + + def _to_timestamp(self, time_value: Union[int, datetime, None]) -> Optional[Timestamp]: + """Convert various time formats to Protobuf Timestamp. + + Args: + time_value: Time value as Unix timestamp (int) or datetime object + + Returns: + Optional[Timestamp]: Protobuf timestamp or None if input is None + """ + if time_value is None: + return None + + timestamp = Timestamp() + if isinstance(time_value, int): + # Handle Unix timestamp (seconds since epoch) + timestamp.FromSeconds(time_value) + elif isinstance(time_value, datetime): + # Handle datetime object + timestamp.FromDatetime(time_value) + return timestamp + + def _convert_order_to_proto(self, mt5_order) -> Order: + """Convert MT5 order object to protobuf Order message. + + Args: + mt5_order: Order information from MT5 + + Returns: + Order: Protobuf Order message + """ + order = Order( + ticket=mt5_order.ticket, + time_setup_msc=mt5_order.time_setup_msc, + time_done_msc=mt5_order.time_done_msc, + type=mt5_order.type, + type_time=mt5_order.type_time, + type_filling=mt5_order.type_filling, + state=mt5_order.state, + magic=mt5_order.magic, + volume_current=float(mt5_order.volume_current), + price_open=float(mt5_order.price_open), + stop_loss=float(mt5_order.sl), + take_profit=float(mt5_order.tp), + price_current=float(mt5_order.price_current), + symbol=mt5_order.symbol, + comment=mt5_order.comment, + external_id=mt5_order.external_id + ) + + # Convert timestamp fields + time_setup = self._to_timestamp(mt5_order.time_setup) + if time_setup: + order.time_setup.CopyFrom(time_setup) + + time_done = self._to_timestamp(mt5_order.time_done) + if time_done: + order.time_done.CopyFrom(time_done) + + time_expiration = self._to_timestamp(mt5_order.time_expiration) + if time_expiration: + order.time_expiration.CopyFrom(time_expiration) + + return order + + def GetOrders(self, request: OrdersGetRequest, context) -> OrdersGetResponse: + """Get orders from MT5 based on specified filters. + + According to MT5 reference, we can filter orders by: + 1. Symbol name + 2. Symbol group + 3. Order ticket + + Args: + request: OrdersGetRequest containing filter criteria + context: gRPC context + + Returns: + OrdersGetResponse containing matched orders or error + """ + response = OrdersGetResponse() + + # Ensure MT5 is initialized + initialized, error = self._ensure_initialized() + if not initialized: + response.error.CopyFrom(error) + return response + + try: + # Apply filters according to MT5 reference + if request.HasField('ticket'): + orders = mt5.orders_get(ticket=request.ticket) + elif request.HasField('symbol'): + orders = mt5.orders_get(symbol=request.symbol) + elif request.HasField('group'): + orders = mt5.orders_get(group=request.group) + else: + # If no filters specified, get all orders + orders = mt5.orders_get() + + if orders is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = f"Failed to get orders: {error_message}" + return response + + # Convert MT5 orders to protobuf messages + for mt5_order in orders: + order_proto = self._convert_order_to_proto(mt5_order) + response.orders.append(order_proto) + + return response + + except Exception as e: + response.error.code = -1 # RES_E_FAIL + response.error.message = f"Internal error processing orders: {str(e)}" + return response + + def GetOrdersTotal(self, request: OrdersTotalRequest, context) -> OrdersTotalResponse: + """Get total number of active orders. + + Args: + request: OrdersTotalRequest + context: gRPC context + + Returns: + OrdersTotalResponse containing total count or error + """ + response = OrdersTotalResponse() + + # Ensure MT5 is initialized + initialized, error = self._ensure_initialized() + if not initialized: + response.error.CopyFrom(error) + return response + + try: + total = mt5.orders_total() + if total is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = f"Failed to get orders total: {error_message}" + return response + + response.total = total + return response + + except Exception as e: + response.error.code = -1 # RES_E_FAIL + response.error.message = f"Internal error getting orders total: {str(e)}" + return response + + def __del__(self): + """Clean up MT5 connection on service shutdown.""" + if self._initialized: + mt5.shutdown() \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/order_calc.py b/mt5_grpc_server/mt5_grpc_server/imp/order_calc.py new file mode 100644 index 0000000..f4f1f17 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/order_calc.py @@ -0,0 +1,57 @@ +import MetaTrader5 as mt5 +from mt5_grpc_proto.order_calc_pb2 import OrderCalcMarginResponse, OrderCalcProfitResponse +from mt5_grpc_proto.order_calc_pb2_grpc import OrderCalcServiceServicer +from mt5_grpc_proto.common_pb2 import Error + + +class OrderCalcServiceImpl(OrderCalcServiceServicer): + def CalcMargin(self, request, context): + """ + Calculate margin required for a trading operation + """ + # Calculate margin using mt5.order_calc_margin + margin = mt5.order_calc_margin( + request.action, + request.symbol, + request.volume, + request.price + ) + + # Check if calculation was successful + if margin is None: + error = mt5.last_error() + return OrderCalcMarginResponse( + margin=0, + error=Error(code=error[0], message=error[1]) + ) + + return OrderCalcMarginResponse( + margin=margin, + error=Error(code=0, message="") + ) + + def CalcProfit(self, request, context): + """ + Calculate potential profit for a trading operation + """ + # Calculate profit using mt5.order_calc_profit + profit = mt5.order_calc_profit( + request.action, + request.symbol, + request.volume, + request.price_open, + request.price_close + ) + + # Check if calculation was successful + if profit is None: + error = mt5.last_error() + return OrderCalcProfitResponse( + profit=0, + error=Error(code=error[0], message=error[1]) + ) + + return OrderCalcProfitResponse( + profit=profit, + error=Error(code=0, message="") + ) \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/order_check.py b/mt5_grpc_server/mt5_grpc_server/imp/order_check.py new file mode 100644 index 0000000..5a9105c --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/order_check.py @@ -0,0 +1,38 @@ +import MetaTrader5 as mt5 +from mt5_grpc_proto.order_check_pb2 import OrderCheckResponse, OrderCheckResult +from mt5_grpc_proto.order_check_pb2_grpc import OrderCheckServiceServicer +from mt5_grpc_proto.common_pb2 import Error + + +class OrderCheckServiceImpl(OrderCheckServiceServicer): + def CheckOrder(self, request, context): + """ + Check if an order can be executed + """ + # Check order using mt5.order_check + result = mt5.order_check(request.trade_request) + + # Check if check was successful + if result is None: + error = mt5.last_error() + return OrderCheckResponse( + error=Error(code=error[0], message=error[1]) + ) + + # Convert result to OrderCheckResult + check_result = OrderCheckResult( + retcode=result.retcode, + balance=result.balance, + equity=result.equity, + profit=result.profit, + margin=result.margin, + margin_free=result.margin_free, + margin_level=result.margin_level, + comment=result.comment, + request=request.trade_request + ) + + return OrderCheckResponse( + check_result=check_result, + error=Error(code=0, message="") + ) \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/positions.py b/mt5_grpc_server/mt5_grpc_server/imp/positions.py new file mode 100644 index 0000000..7a5d502 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/positions.py @@ -0,0 +1,183 @@ +import MetaTrader5 as mt5 +from datetime import datetime +from typing import Optional, Tuple, Union +from google.protobuf.timestamp_pb2 import Timestamp +from mt5_grpc_proto.common_pb2 import Error +from mt5_grpc_proto.position_pb2 import ( + PositionsGetRequest, + PositionsGetResponse, + PositionsTotalRequest, + PositionsTotalResponse, + Position +) +from mt5_grpc_proto.position_pb2_grpc import PositionsServiceServicer + + +class PositionsServiceImpl(PositionsServiceServicer): + """Implementation of Positions service for MetaTrader 5.""" + + def __init__(self): + self._initialized = False + + def _ensure_initialized(self) -> Tuple[bool, Optional[Error]]: + """Initialize MT5 connection if not already initialized. + + Returns: + Tuple[bool, Optional[Error]]: Success status and error if any + """ + if not self._initialized: + if not mt5.initialize(): + error_code, error_message = mt5.last_error() + error = Error( + code=error_code, + message=f"MetaTrader5 initialization failed: {error_message}" + ) + return False, error + self._initialized = True + return True, None + + def _to_timestamp(self, time_value: Union[int, datetime, None]) -> Optional[Timestamp]: + """Convert various time formats to Protobuf Timestamp. + + Args: + time_value: Time value as Unix timestamp (int) or datetime object + + Returns: + Optional[Timestamp]: Protobuf timestamp or None if input is None + """ + if time_value is None: + return None + + timestamp = Timestamp() + if isinstance(time_value, int): + # Handle Unix timestamp (seconds since epoch) + timestamp.FromSeconds(time_value) + elif isinstance(time_value, datetime): + # Handle datetime object + timestamp.FromDatetime(time_value) + return timestamp + + def _convert_position_to_proto(self, mt5_position) -> Position: + """Convert MT5 position object to protobuf Position message. + + Args: + mt5_position: Position information from MT5 + + Returns: + Position: Protobuf Position message + """ + position = Position( + ticket=mt5_position.ticket, + symbol=mt5_position.symbol, + type=mt5_position.type, + magic=mt5_position.magic, + identifier=mt5_position.identifier, + reason=mt5_position.reason, + volume=float(mt5_position.volume), + price_open=float(mt5_position.price_open), + stop_loss=float(mt5_position.sl), + take_profit=float(mt5_position.tp), + price_current=float(mt5_position.price_current), + swap=float(mt5_position.swap), + profit=float(mt5_position.profit), + comment=mt5_position.comment + ) + + # Convert time field + time = self._to_timestamp(mt5_position.time) + if time: + position.time.CopyFrom(time) + + return position + + def GetPositions(self, request: PositionsGetRequest, context) -> PositionsGetResponse: + """Get open positions from MT5 based on specified filters. + + According to MT5 reference, we can filter positions by: + 1. Symbol name + 2. Symbol group + 3. Position ticket + + Args: + request: PositionsGetRequest containing filter criteria + context: gRPC context + + Returns: + PositionsGetResponse containing matched positions or error + """ + response = PositionsGetResponse() + + # Ensure MT5 is initialized + initialized, error = self._ensure_initialized() + if not initialized: + response.error.CopyFrom(error) + return response + + try: + # Apply filters according to MT5 reference + if request.HasField('ticket'): + positions = mt5.positions_get(ticket=request.ticket) + elif request.HasField('symbol'): + positions = mt5.positions_get(symbol=request.symbol) + elif request.HasField('group'): + positions = mt5.positions_get(group=request.group) + else: + # If no filters specified, get all positions + positions = mt5.positions_get() + + if positions is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = f"Failed to get positions: {error_message}" + return response + + # Convert MT5 positions to protobuf messages + for mt5_position in positions: + position_proto = self._convert_position_to_proto(mt5_position) + response.positions.append(position_proto) + + return response + + except Exception as e: + response.error.code = -1 # RES_E_FAIL + response.error.message = f"Internal error processing positions: {str(e)}" + return response + + def GetPositionsTotal(self, request: PositionsTotalRequest, context) -> PositionsTotalResponse: + """Get total number of open positions. + + Args: + request: PositionsTotalRequest + context: gRPC context + + Returns: + PositionsTotalResponse containing total count or error + """ + response = PositionsTotalResponse() + + # Ensure MT5 is initialized + initialized, error = self._ensure_initialized() + if not initialized: + response.error.CopyFrom(error) + return response + + try: + total = mt5.positions_total() + if total is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = f"Failed to get positions total: {error_message}" + return response + + response.total = total + return response + + except Exception as e: + response.error.code = -1 # RES_E_FAIL + response.error.message = f"Internal error getting positions total: {str(e)}" + return response + + def __del__(self): + """Clean up MT5 connection on service shutdown.""" + if self._initialized: + mt5.shutdown() \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/symbol_info.py b/mt5_grpc_server/mt5_grpc_server/imp/symbol_info.py new file mode 100644 index 0000000..f634fc2 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/symbol_info.py @@ -0,0 +1,164 @@ +import MetaTrader5 as mt5 +from google.protobuf.timestamp_pb2 import Timestamp +from mt5_grpc_proto.symbol_info_pb2 import SymbolInfo, SymbolInfoResponse +from mt5_grpc_proto.symbol_info_pb2_grpc import SymbolInfoServiceServicer + + +class SymbolInfoServiceImpl(SymbolInfoServiceServicer): + def GetSymbolInfo(self, request, context): + """ + Implements the GetSymbolInfo RPC method. + Returns detailed information about a specified symbol from MetaTrader 5. + """ + # Initialize the response + response = SymbolInfoResponse() + + # Check if MT5 is initialized + if not mt5.initialize(): + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = error_message + return response + + try: + # Get symbol info from MT5 + symbol_info = mt5.symbol_info(request.symbol) + + if symbol_info is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = error_message + return response + + # Create SymbolInfo message and populate it with MT5 data + info = SymbolInfo() + + # Boolean properties + info.custom = symbol_info.custom + info.select = symbol_info.select + info.visible = symbol_info.visible + info.spread_float = symbol_info.spread_float + info.margin_hedged_use_leg = symbol_info.margin_hedged_use_leg + + # Integer properties + info.chart_mode = symbol_info.chart_mode + info.session_deals = symbol_info.session_deals + info.session_buy_orders = symbol_info.session_buy_orders + info.session_sell_orders = symbol_info.session_sell_orders + info.volume = symbol_info.volume + info.volumehigh = symbol_info.volumehigh + info.volumelow = symbol_info.volumelow + info.digits = symbol_info.digits + info.spread = symbol_info.spread + info.ticks_bookdepth = symbol_info.ticks_bookdepth + info.trade_calc_mode = symbol_info.trade_calc_mode + info.trade_mode = symbol_info.trade_mode + info.trade_stops_level = symbol_info.trade_stops_level + info.trade_freeze_level = symbol_info.trade_freeze_level + info.trade_exemode = symbol_info.trade_exemode + info.swap_mode = symbol_info.swap_mode + info.swap_rollover3days = symbol_info.swap_rollover3days + info.expiration_mode = symbol_info.expiration_mode + info.filling_mode = symbol_info.filling_mode + info.order_mode = symbol_info.order_mode + info.order_gtc_mode = symbol_info.order_gtc_mode + info.option_mode = symbol_info.option_mode + info.option_right = symbol_info.option_right + + # Timestamp properties + if hasattr(symbol_info, 'time'): + timestamp = Timestamp() + timestamp.FromSeconds(int(symbol_info.time)) + info.time.CopyFrom(timestamp) + + if hasattr(symbol_info, 'start_time'): + start_time = Timestamp() + start_time.FromSeconds(int(symbol_info.start_time)) + info.start_time.CopyFrom(start_time) + + if hasattr(symbol_info, 'expiration_time'): + expiration_time = Timestamp() + expiration_time.FromSeconds(int(symbol_info.expiration_time)) + info.expiration_time.CopyFrom(expiration_time) + + # Double properties + info.bid = symbol_info.bid + info.bidhigh = symbol_info.bidhigh + info.bidlow = symbol_info.bidlow + info.ask = symbol_info.ask + info.askhigh = symbol_info.askhigh + info.asklow = symbol_info.asklow + info.last = symbol_info.last + info.lasthigh = symbol_info.lasthigh + info.lastlow = symbol_info.lastlow + info.volume_real = symbol_info.volume_real + info.volumehigh_real = symbol_info.volumehigh_real + info.volumelow_real = symbol_info.volumelow_real + info.option_strike = symbol_info.option_strike + info.point = symbol_info.point + info.trade_tick_value = symbol_info.trade_tick_value + info.trade_tick_value_profit = symbol_info.trade_tick_value_profit + info.trade_tick_value_loss = symbol_info.trade_tick_value_loss + info.trade_tick_size = symbol_info.trade_tick_size + info.trade_contract_size = symbol_info.trade_contract_size + info.trade_accrued_interest = symbol_info.trade_accrued_interest + info.trade_face_value = symbol_info.trade_face_value + info.trade_liquidity_rate = symbol_info.trade_liquidity_rate + info.volume_min = symbol_info.volume_min + info.volume_max = symbol_info.volume_max + info.volume_step = symbol_info.volume_step + info.volume_limit = symbol_info.volume_limit + info.swap_long = symbol_info.swap_long + info.swap_short = symbol_info.swap_short + info.margin_initial = symbol_info.margin_initial + info.margin_maintenance = symbol_info.margin_maintenance + info.session_volume = symbol_info.session_volume + info.session_turnover = symbol_info.session_turnover + info.session_interest = symbol_info.session_interest + info.session_buy_orders_volume = symbol_info.session_buy_orders_volume + info.session_sell_orders_volume = symbol_info.session_sell_orders_volume + info.session_open = symbol_info.session_open + info.session_close = symbol_info.session_close + info.session_aw = symbol_info.session_aw + info.session_price_settlement = symbol_info.session_price_settlement + info.session_price_limit_min = symbol_info.session_price_limit_min + info.session_price_limit_max = symbol_info.session_price_limit_max + info.margin_hedged = symbol_info.margin_hedged + info.price_change = symbol_info.price_change + info.price_volatility = symbol_info.price_volatility + info.price_theoretical = symbol_info.price_theoretical + info.price_greeks_delta = symbol_info.price_greeks_delta + info.price_greeks_theta = symbol_info.price_greeks_theta + info.price_greeks_gamma = symbol_info.price_greeks_gamma + info.price_greeks_vega = symbol_info.price_greeks_vega + info.price_greeks_rho = symbol_info.price_greeks_rho + info.price_greeks_omega = symbol_info.price_greeks_omega + info.price_sensitivity = symbol_info.price_sensitivity + + # String properties + info.basis = symbol_info.basis + info.category = symbol_info.category + info.currency_base = symbol_info.currency_base + info.currency_profit = symbol_info.currency_profit + info.currency_margin = symbol_info.currency_margin + info.bank = symbol_info.bank + info.description = symbol_info.description + info.exchange = symbol_info.exchange + info.formula = symbol_info.formula + info.isin = symbol_info.isin + info.name = symbol_info.name + info.page = symbol_info.page + info.path = symbol_info.path + + # Set the symbol_info field in the response + response.symbol_info.CopyFrom(info) + + return response + + except Exception as e: + response.error.code = -1 # Generic error code for exceptions + response.error.message = str(e) + return response + + finally: + mt5.shutdown() \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/symbol_info_tick.py b/mt5_grpc_server/mt5_grpc_server/imp/symbol_info_tick.py new file mode 100644 index 0000000..8533968 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/symbol_info_tick.py @@ -0,0 +1,61 @@ +import MetaTrader5 as mt5 +from google.protobuf.timestamp_pb2 import Timestamp +from mt5_grpc_proto.symbol_info_tick_pb2 import SymbolInfoTick, SymbolInfoTickResponse +from mt5_grpc_proto.symbol_info_tick_pb2_grpc import SymbolInfoTickServiceServicer + + +class SymbolInfoTickServiceImpl(SymbolInfoTickServiceServicer): + def GetSymbolInfoTick(self, request, context): + """ + Implements the GetSymbolInfoTick RPC method. + Returns the last tick information for a specified symbol from MetaTrader 5. + """ + # Initialize the response + response = SymbolInfoTickResponse() + + # Check if MT5 is initialized + if not mt5.initialize(): + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = error_message + return response + + try: + # Get symbol info tick from MT5 + tick_info = mt5.symbol_info_tick(request.symbol) + + if tick_info is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = error_message + return response + + # Create SymbolInfoTick message and populate it with MT5 data + tick = SymbolInfoTick() + + # Create and set timestamp + timestamp = Timestamp() + timestamp.FromSeconds(int(tick_info.time)) + tick.time.CopyFrom(timestamp) + + # Set numeric fields + tick.bid = tick_info.bid + tick.ask = tick_info.ask + tick.last = tick_info.last + tick.volume = tick_info.volume + tick.time_msc = tick_info.time_msc + tick.flags = tick_info.flags + tick.volume_real = tick_info.volume_real + + # Set the tick field in the response + response.tick.CopyFrom(tick) + + return response + + except Exception as e: + response.error.code = -1 # Generic error code for exceptions + response.error.message = str(e) + return response + + finally: + mt5.shutdown() \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/symbols.py b/mt5_grpc_server/mt5_grpc_server/imp/symbols.py new file mode 100644 index 0000000..5b03fe3 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/symbols.py @@ -0,0 +1,57 @@ +import MetaTrader5 as mt5 +from mt5_grpc_proto.symbols_pb2 import ( + SymbolsTotalResponse, SymbolsGetResponse, SymbolSelectResponse +) +from mt5_grpc_proto.symbols_pb2_grpc import SymbolsServiceServicer +from mt5_grpc_proto.common_pb2 import Error + + +class SymbolsServiceImpl(SymbolsServiceServicer): + def GetSymbolsTotal(self, request, context): + """Get the number of all financial instruments""" + total = mt5.symbols_total() + + if total is None: + error = mt5.last_error() + return SymbolsTotalResponse( + error=Error(code=error[0], message=error[1]) + ) + + return SymbolsTotalResponse( + total=total, + error=Error(code=0, message="") + ) + + def GetSymbols(self, request, context): + """Get all financial instruments""" + symbols = mt5.symbols_get(group=request.group if request.group else "*") + + if symbols is None: + error = mt5.last_error() + return SymbolsGetResponse( + error=Error(code=error[0], message=error[1]) + ) + + return SymbolsGetResponse( + symbols=[symbol.name for symbol in symbols], + error=Error(code=0, message="") + ) + + def SelectSymbol(self, request, context): + """Select a symbol in the Market Watch window""" + success = mt5.symbol_select( + request.symbol, + request.enable + ) + + if not success: + error = mt5.last_error() + return SymbolSelectResponse( + success=False, + error=Error(code=error[0], message=error[1]) + ) + + return SymbolSelectResponse( + success=True, + error=Error(code=0, message="") + ) \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/terminal_info.py b/mt5_grpc_server/mt5_grpc_server/imp/terminal_info.py new file mode 100644 index 0000000..6d60ecb --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/terminal_info.py @@ -0,0 +1,42 @@ +import MetaTrader5 as mt5 +from mt5_grpc_proto.terminal_pb2 import TerminalInfoResponse +from mt5_grpc_proto.terminal_pb2_grpc import TerminalInfoServiceServicer +from mt5_grpc_proto.common_pb2 import Error + + +class TerminalInfoServiceImpl(TerminalInfoServiceServicer): + def GetTerminalInfo(self, request, context): + """Get MetaTrader 5 terminal information""" + terminal_info = mt5.terminal_info() + + if terminal_info is None: + error = mt5.last_error() + return TerminalInfoResponse( + error=Error(code=error[0], message=error[1]) + ) + + return TerminalInfoResponse( + community_account=terminal_info.community_account, + community_connection=terminal_info.community_connection, + connected=terminal_info.connected, + dlls_allowed=terminal_info.dlls_allowed, + trade_allowed=terminal_info.trade_allowed, + tradeapi_disabled=terminal_info.tradeapi_disabled, + email_enabled=terminal_info.email_enabled, + ftp_enabled=terminal_info.ftp_enabled, + notifications_enabled=terminal_info.notifications_enabled, + mqid=terminal_info.mqid, + build=terminal_info.build, + maxbars=terminal_info.maxbars, + codepage=terminal_info.codepage, + ping_last=terminal_info.ping_last, + community_balance=terminal_info.community_balance, + retransmission=terminal_info.retransmission, + company=terminal_info.company, + name=terminal_info.name, + language=terminal_info.language, + path=terminal_info.path, + data_path=terminal_info.data_path, + commondata_path=terminal_info.commondata_path, + error=Error(code=0, message="") + ) \ No newline at end of file diff --git a/mt5_grpc_server/mt5_grpc_server/imp/trade.py b/mt5_grpc_server/mt5_grpc_server/imp/trade.py new file mode 100644 index 0000000..e250f07 --- /dev/null +++ b/mt5_grpc_server/mt5_grpc_server/imp/trade.py @@ -0,0 +1,92 @@ +import MetaTrader5 as mt5 +from mt5_grpc_proto.trade_pb2 import TradeResult, OrderSendResponse +from mt5_grpc_proto.trade_pb2_grpc import OrderSendServiceServicer + + +class OrderSendServiceImpl(OrderSendServiceServicer): + def SendOrder(self, request, context): + """ + Implements the SendOrder RPC method. + Sends a trading order to MetaTrader 5. + """ + # Initialize the response + response = OrderSendResponse() + + # Check if MT5 is initialized + if not mt5.initialize(): + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = error_message + return response + + try: + # Create MT5 request structure + mt5_request = { + "action": request.trade_request.action, + "magic": request.trade_request.magic, + "volume": request.trade_request.volume, + "deviation": request.trade_request.deviation, + "type": request.trade_request.type, + "type_filling": request.trade_request.type_filling, + "type_time": request.trade_request.type_time, + } + + # Add optional fields if they are set + if request.trade_request.HasField('order'): + mt5_request["order"] = request.trade_request.order + if request.trade_request.HasField('symbol'): + mt5_request["symbol"] = request.trade_request.symbol + if request.trade_request.HasField('price'): + mt5_request["price"] = request.trade_request.price + if request.trade_request.HasField('stoplimit'): + mt5_request["stoplimit"] = request.trade_request.stoplimit + if request.trade_request.HasField('sl'): + mt5_request["sl"] = request.trade_request.sl + if request.trade_request.HasField('tp'): + mt5_request["tp"] = request.trade_request.tp + if request.trade_request.HasField('expiration'): + mt5_request["expiration"] = request.trade_request.expiration.seconds + if request.trade_request.HasField('comment'): + mt5_request["comment"] = request.trade_request.comment + if request.trade_request.HasField('position'): + mt5_request["position"] = request.trade_request.position + if request.trade_request.HasField('position_by'): + mt5_request["position_by"] = request.trade_request.position_by + + # Send order to MT5 + result = mt5.order_send(mt5_request) + + if result is None: + error_code, error_message = mt5.last_error() + response.error.code = error_code + response.error.message = error_message + return response + + # Create TradeResult message and populate it with MT5 data + trade_result = TradeResult() + trade_result.retcode = result.retcode + trade_result.deal = result.deal + trade_result.order = result.order + trade_result.volume = result.volume + trade_result.price = result.price + trade_result.bid = result.bid + trade_result.ask = result.ask + trade_result.comment = result.comment + trade_result.request_id = result.request_id + trade_result.retcode_external = result.retcode_external + + # Copy the original request + trade_result.request.CopyFrom(request.trade_request) + + # Set the trade_result field in the response + response.trade_result.CopyFrom(trade_result) + + return response + + except Exception as e: + response.error.code = -1 # Generic error code for exceptions + response.error.message = str(e) + return response + + finally: + mt5.shutdown() \ No newline at end of file diff --git a/mt5_grpc_server/pyproject.toml b/mt5_grpc_server/pyproject.toml new file mode 100644 index 0000000..1b68d94 --- /dev/null +++ b/mt5_grpc_server/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/mt5_grpc_server/requirements.txt b/mt5_grpc_server/requirements.txt new file mode 100644 index 0000000..cd683a0 --- /dev/null +++ b/mt5_grpc_server/requirements.txt @@ -0,0 +1,5 @@ +-e ../mt5_grpc_proto +grpcio>=1.68.1 +grpcio-tools>=1.68.1 +protobuf>=5.29.2 +MetaTrader5>=5.0.33 \ No newline at end of file diff --git a/mt5_grpc_server/setup.py b/mt5_grpc_server/setup.py new file mode 100644 index 0000000..7088b21 --- /dev/null +++ b/mt5_grpc_server/setup.py @@ -0,0 +1,57 @@ +from setuptools import setup, find_packages + +setup( + name="mt5_grpc_server", + version="0.1.0", + description="MetaTrader 5 gRPC Server for remote trading operations", + long_description=open("README.md").read(), + long_description_content_type="text/markdown", + author="starmel", + author_email="slava.kornienko16@gmail.com", + url="https://github.com/Starmel/Metatrader5-gRPC-server", + packages=find_packages(), + install_requires=[ + "grpcio>=1.68.1", + "grpcio-tools>=1.68.1", + "protobuf>=5.29.2", + "pytz>=2024.2", + "MetaTrader5>=5.0.33", + "mt5_grpc_proto>=0.1.0" + ], + extras_require={ + 'dev': [ + 'pytest>=7.0.0', + 'pytest-cov>=4.0.0', + 'black>=23.0.0', + 'isort>=5.0.0', + 'mypy>=1.0.0', + 'build>=1.0.0', + 'twine>=4.0.0', + ], + }, + entry_points={ + "console_scripts": [ + "mt5-grpc-server=mt5_grpc_server.grpc_server:main", + ], + }, + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Intended Audience :: Financial and Insurance Industry", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "License :: OSI Approved :: MIT License", + "Operating System :: Microsoft :: Windows", + "Topic :: Office/Business :: Financial :: Investment", + "Topic :: Software Development :: Libraries :: Python Modules", + ], + python_requires=">=3.8", + keywords="metatrader, mt5, trading, grpc, server, api", + project_urls={ + "Documentation": "https://github.com/Starmel/Metatrader5-gRPC-server/tree/main/docs", + "Source": "https://github.com/Starmel/Metatrader5-gRPC-server", + "Tracker": "https://github.com/Starmel/Metatrader5-gRPC-server/issues", + }, +) diff --git a/protos/account.proto b/protos/account.proto index 84cc5aa..d8fa4b8 100644 --- a/protos/account.proto +++ b/protos/account.proto @@ -1,80 +1,60 @@ syntax = "proto3"; -package trading_account; +package metatrader.v1; -import "google/protobuf/timestamp.proto"; +import "common.proto"; -// Account Trade Mode Enumeration -enum AccountTradeMode { - ACCOUNT_TRADE_MODE_DEMO = 0; - ACCOUNT_TRADE_MODE_CONTEST = 1; - ACCOUNT_TRADE_MODE_REAL = 2; -} - -// Account Stopout Mode Enumeration -enum AccountStopoutMode { - ACCOUNT_STOPOUT_MODE_PERCENT = 0; - ACCOUNT_STOPOUT_MODE_MONEY = 1; -} - -// Account Margin Mode Enumeration -enum AccountMarginMode { - ACCOUNT_MARGIN_MODE_RETAIL_NETTING = 0; - ACCOUNT_MARGIN_MODE_EXCHANGE = 1; - ACCOUNT_MARGIN_MODE_RETAIL_HEDGING = 2; -} - -// Comprehensive Account Information Message +// Account Information Message message AccountInfo { - // Integer Properties - int64 login = 1; - AccountTradeMode trade_mode = 2; - int64 leverage = 3; - int32 limit_orders = 4; - AccountStopoutMode margin_so_mode = 5; - AccountMarginMode margin_mode = 6; - int32 currency_digits = 7; - - // Boolean Properties - bool trade_allowed = 8; - bool trade_expert = 9; - bool fifo_close = 10; - bool hedge_allowed = 11; - - // Financial Properties - double balance = 12; - double credit = 13; - double profit = 14; - double equity = 15; - double margin = 16; - double margin_free = 17; - double margin_level = 18; - - // Margin-related Properties - double margin_so_call = 19; - double margin_so_so = 20; - double margin_initial = 21; - double margin_maintenance = 22; - - // Additional Financial Properties - double assets = 23; - double liabilities = 24; - double commission_blocked = 25; + // Integer Properties + int64 login = 1; + int32 trade_mode = 2; + int32 leverage = 3; + int32 limit_orders = 4; + int32 margin_so_mode = 5; + int32 margin_mode = 6; + int32 currency_digits = 7; + + // Boolean Properties + bool trade_allowed = 10; + bool trade_expert = 11; + bool fifo_close = 12; + + // Double Properties + double balance = 20; + double credit = 21; + double profit = 22; + double equity = 23; + double margin = 24; + double margin_free = 25; + double margin_level = 26; + double margin_so_call = 27; + double margin_so_so = 28; + double margin_initial = 29; + double margin_maintenance = 30; + double assets = 31; + double liabilities = 32; + double commission_blocked = 33; + + // String Properties + string name = 40; + string server = 41; + string currency = 42; + string company = 43; +} - // String Properties - string name = 26; - string server = 27; - string currency = 28; - string company = 29; +// Request for Account Information +// Empty request since no parameters are needed +message AccountInfoRequest {} - // Metadata - google.protobuf.Timestamp timestamp = 30; +// Response for Account Information +message AccountInfoResponse { + AccountInfo account_info = 1; + Error error = 2; } -// Account Information Service +// Service definition for Account Information service AccountInfoService { - // Retrieve current account information - rpc GetAccountInfo(Empty) returns (AccountInfo) {} -} - -message Empty {} + // Get information about the current trading account + rpc GetAccountInfo(AccountInfoRequest) returns (AccountInfoResponse); +} \ No newline at end of file diff --git a/protos/common.proto b/protos/common.proto new file mode 100644 index 0000000..1e13517 --- /dev/null +++ b/protos/common.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +package metatrader.v1; + +// Error details +message Error { + int32 code = 1; + string message = 2; +} + +// Request for getting the last error +message GetLastErrorRequest {} + +// Response for getting the last error +message GetLastErrorResponse { + Error error = 1; +} + +// Service definition +service MetaTraderService { + rpc Connect(ConnectRequest) returns (Error); + rpc GetLastError(Empty) returns (GetLastErrorResponse); +} + +message Empty {} + +message ConnectRequest { + optional string path = 1; // Optional path to MetaTrader executable, use default if not specified +} + +message TimeFilter { + int64 date_from = 1; // Unix timestamp in seconds since 1970.01.01 + int64 date_to = 2; // Unix timestamp in seconds since 1970.01.01 +} \ No newline at end of file diff --git a/protos/current_tick.proto b/protos/current_tick.proto deleted file mode 100644 index 09fd59b..0000000 --- a/protos/current_tick.proto +++ /dev/null @@ -1,90 +0,0 @@ -syntax = "proto3"; - -package market_data; - -import "google/protobuf/timestamp.proto"; - -// Tick Flags Enumeration -enum TickFlags { - TICK_FLAG_NONE = 0; - TICK_FLAG_BID = 1; // Bid price changed - TICK_FLAG_ASK = 2; // Ask price changed - TICK_FLAG_LAST = 4; // Last deal price changed - TICK_FLAG_VOLUME = 8; // Volume changed - TICK_FLAG_BUY = 16; // Tick is a result of a buy deal - TICK_FLAG_SELL = 32; // Tick is a result of a sell deal -} - -// Tick Data Structure -message SymbolTick { - // Time of the last prices update - google.protobuf.Timestamp time = 1; - - // Millisecond-precise timestamp - int64 time_msc = 2; - - // Price information - double bid = 3; // Current Bid price - double ask = 4; // Current Ask price - double last = 5; // Price of the last deal - - // Volume information - uint64 volume = 6; // Volume for the current last price (integer) - double volume_real = 7; // Volume with greater accuracy - - // Tick flags - repeated TickFlags flags = 8; -} - -// Symbol Info Request -message SymbolInfoRequest { - string symbol = 1; // Symbol name to fetch tick data for -} - -// Symbol Info Service -service SymbolInfoService { - // Get the latest tick for a specific symbol - rpc GetLatestTick(SymbolInfoRequest) returns (SymbolTick) {} - - // Get historical ticks with filtering options - rpc GetTickHistory(TickHistoryRequest) returns (TickHistoryResponse) {} -} - -// Tick History Request with Advanced Filtering -message TickHistoryRequest { - string symbol = 1; // Symbol name - google.protobuf.Timestamp from_time = 2; - google.protobuf.Timestamp to_time = 3; - - // Optional filtering - bool include_bid_changes = 4; - bool include_ask_changes = 5; - bool include_last_price_changes = 6; - bool include_volume_changes = 7; - bool include_buy_ticks = 8; - bool include_sell_ticks = 9; - - // Pagination - uint32 page_size = 10; - uint32 page_token = 11; -} - -// Tick History Response -message TickHistoryResponse { - repeated SymbolTick ticks = 1; - uint32 total_count = 2; - uint32 next_page_token = 3; -} - -// Error Details for Tick Retrieval -message TickErrorDetails { - enum ErrorCode { - SYMBOL_NOT_FOUND = 0; - DATA_RETRIEVAL_FAILED = 1; - NETWORK_ERROR = 2; - RATE_LIMIT_EXCEEDED = 3; - } - - ErrorCode code = 1; - string message = 2; -} \ No newline at end of file diff --git a/protos/deal.proto b/protos/deal.proto index c2480ea..97296e7 100644 --- a/protos/deal.proto +++ b/protos/deal.proto @@ -2,110 +2,48 @@ syntax = "proto3"; package metatrader.v1; -import "google/protobuf/timestamp.proto"; import "common.proto"; -// Service definition for history deals operations -service HistoryDealService { - // Get deals based on different filter criteria - rpc GetHistoryDeals(GetHistoryDealsRequest) returns (GetHistoryDealsResponse) {} +// Service definition for dealing with trade history +service TradeHistoryService { + // Get deals from trading history within specified parameters + rpc GetDeals(DealsRequest) returns (DealsResponse); } -// Request message for getting history deals -message GetHistoryDealsRequest { +// Request message for retrieving deals +message DealsRequest { oneof filter { TimeFilter time_filter = 1; - int64 ticket = 2; // Filter by order ticket - int64 position = 3; // Filter by position ticket + uint64 ticket = 2; // Filter by order ticket + uint64 position = 3; // Filter by position ticket } - optional string group = 4; // Optional symbol group filter + optional string group = 4; // Optional symbol group filter } -// Time filter for history deals -message TimeFilter { - google.protobuf.Timestamp date_from = 1; - google.protobuf.Timestamp date_to = 2; -} - -// Response message containing history deals -message GetHistoryDealsResponse { +// Response containing a list of deals +message DealsResponse { repeated Deal deals = 1; optional Error error = 2; } -// Deal details +// Represents a single trade deal message Deal { - // Integer properties - int64 ticket = 1; // DEAL_TICKET - int64 order = 2; // DEAL_ORDER - google.protobuf.Timestamp time = 3; // DEAL_TIME - int64 time_msc = 4; // DEAL_TIME_MSC - DealType type = 5; // DEAL_TYPE - DealEntry entry = 6; // DEAL_ENTRY - int64 magic = 7; // DEAL_MAGIC - DealReason reason = 8; // DEAL_REASON - int64 position_id = 9; // DEAL_POSITION_ID - - // Double properties - double volume = 10; // DEAL_VOLUME - double price = 11; // DEAL_PRICE - double commission = 12; // DEAL_COMMISSION - double swap = 13; // DEAL_SWAP - double profit = 14; // DEAL_PROFIT - double fee = 15; // DEAL_FEE - double sl = 16; // DEAL_SL (Stop Loss) - double tp = 17; // DEAL_TP (Take Profit) - - // String properties - string symbol = 18; // DEAL_SYMBOL - string comment = 19; // DEAL_COMMENT - string external_id = 20; // DEAL_EXTERNAL_ID -} - -// Deal type enumeration (ENUM_DEAL_TYPE) -enum DealType { - DEAL_TYPE_UNSPECIFIED = 0; - DEAL_TYPE_BUY = 1; - DEAL_TYPE_SELL = 2; - DEAL_TYPE_BALANCE = 3; - DEAL_TYPE_CREDIT = 4; - DEAL_TYPE_CHARGE = 5; - DEAL_TYPE_CORRECTION = 6; - DEAL_TYPE_BONUS = 7; - DEAL_TYPE_COMMISSION = 8; - DEAL_TYPE_COMMISSION_DAILY = 9; - DEAL_TYPE_COMMISSION_MONTHLY = 10; - DEAL_TYPE_COMMISSION_AGENT_DAILY = 11; - DEAL_TYPE_COMMISSION_AGENT_MONTHLY = 12; - DEAL_TYPE_INTEREST = 13; - DEAL_TYPE_BUY_CANCELED = 14; - DEAL_TYPE_SELL_CANCELED = 15; - DEAL_TYPE_DIVIDEND = 16; - DEAL_TYPE_DIVIDEND_FRANKED = 17; - DEAL_TYPE_TAX = 18; -} - -// Deal entry type enumeration (ENUM_DEAL_ENTRY) -enum DealEntry { - DEAL_ENTRY_UNSPECIFIED = 0; - DEAL_ENTRY_IN = 1; // Entry in - DEAL_ENTRY_OUT = 2; // Entry out - DEAL_ENTRY_INOUT = 3; // Reverse - DEAL_ENTRY_OUT_BY = 4; // Close by opposite position -} - -// Deal reason enumeration (ENUM_DEAL_REASON) -enum DealReason { - DEAL_REASON_UNSPECIFIED = 0; - DEAL_REASON_CLIENT = 1; // From desktop terminal - DEAL_REASON_MOBILE = 2; // From mobile application - DEAL_REASON_WEB = 3; // From web platform - DEAL_REASON_EXPERT = 4; // From MQL5 program - DEAL_REASON_SL = 5; // Stop Loss activation - DEAL_REASON_TP = 6; // Take Profit activation - DEAL_REASON_SO = 7; // Stop Out event - DEAL_REASON_ROLLOVER = 8; // Rollover - DEAL_REASON_VMARGIN = 9; // Variation margin - DEAL_REASON_SPLIT = 10; // Split - DEAL_REASON_CORPORATE_ACTION = 11; // Corporate action + uint64 ticket = 1; // Deal ticket + uint64 order = 2; // Order ticket + int64 time = 3; // Unix timestamp in seconds + int64 time_msc = 4; // Time in milliseconds since epoch + int32 type = 5; // Deal type + int32 entry = 6; // Entry type + uint32 magic = 7; // Magic number + uint64 position_id = 8; // Position identifier + int32 reason = 9; // Deal reason + double volume = 10; // Deal volume + double price = 11; // Deal price + double commission = 12; // Commission + double swap = 13; // Swap + double profit = 14; // Profit + double fee = 15; // Fee + string symbol = 16; // Symbol name + string comment = 17; // Comment + string external_id = 18; // External ID } \ No newline at end of file diff --git a/protos/history_orders.proto b/protos/history_orders.proto new file mode 100644 index 0000000..907d188 --- /dev/null +++ b/protos/history_orders.proto @@ -0,0 +1,69 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; +import "google/protobuf/timestamp.proto"; + +// Service definition for historical orders +service HistoryOrdersService { + // Get orders from trading history within specified parameters + rpc GetHistoryOrders(HistoryOrdersRequest) returns (HistoryOrdersResponse); + + // Get total number of orders in history for a specified period + rpc GetHistoryOrdersTotal(HistoryOrdersTotalRequest) returns (HistoryOrdersTotalResponse); +} + +// Request message for retrieving historical orders +message HistoryOrdersRequest { + oneof filter { + TimeFilter time_filter = 1; + uint64 ticket = 2; // Filter by order ticket + uint64 position = 3; // Filter by position ticket + } + optional string group = 4; // Optional symbol group filter +} + +// Request for getting total number of historical orders +message HistoryOrdersTotalRequest { + int64 date_from = 1; // Unix timestamp in seconds since 1970.01.01 + int64 date_to = 2; // Unix timestamp in seconds since 1970.01.01 +} + +// Response containing total number of historical orders +message HistoryOrdersTotalResponse { + int32 total = 1; + optional Error error = 2; +} + +// Response containing a list of historical orders +message HistoryOrdersResponse { + repeated HistoryOrder orders = 1; + optional Error error = 2; +} + +// Represents a single historical order +message HistoryOrder { + uint64 ticket = 1; // Order ticket + google.protobuf.Timestamp time_setup = 2; // Order setup time + int64 time_setup_msc = 3; // Setup time in milliseconds + google.protobuf.Timestamp time_done = 4; // Order execution/cancellation time + int64 time_done_msc = 5; // Execution time in milliseconds + google.protobuf.Timestamp time_expiration = 6; // Order expiration time + int32 type = 7; // Order type + int32 type_time = 8; // Order time in force + int32 type_filling = 9; // Order filling type + int32 state = 10; // Order state + uint32 magic = 11; // Expert Advisor ID + uint64 position_id = 12; // Position identifier + double volume_initial = 13; // Initial order volume + double volume_current = 14; // Unfilled volume + double price_open = 15; // Order price + double stop_loss = 16; // Stop Loss level + double take_profit = 17; // Take Profit level + double price_current = 18; // Current price + double price_stoplimit = 19; // Stop Limit order activation price + string symbol = 20; // Trading symbol + string comment = 21; // Order comment + string external_id = 22; // Order identifier in an external system +} \ No newline at end of file diff --git a/protos/initialize.proto b/protos/initialize.proto new file mode 100644 index 0000000..9dfbfe9 --- /dev/null +++ b/protos/initialize.proto @@ -0,0 +1,62 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; + +service InitializeService { + + // Connect to the specified trading account + rpc Login(LoginRequest) returns (LoginResponse) {} + + // Shut down connection to the MetaTrader 5 terminal + rpc Shutdown(ShutdownRequest) returns (ShutdownResponse) {} + + // Get the MetaTrader 5 terminal version + rpc GetVersion(VersionRequest) returns (VersionResponse) {} +} + +// Request for login +message LoginRequest { + // Account number + int64 login = 1; + + // Password + string password = 2; + + // Trade server + string server = 3; +} + +// Response for login +message LoginResponse { + // Success flag + bool success = 1; + + // Common error information + Error error = 2; +} + +// Request for shutdown +message ShutdownRequest {} + +// Response for shutdown +message ShutdownResponse { + // Success flag + bool success = 1; + + // Common error information + Error error = 2; +} + +// Request for version +message VersionRequest {} + +// Response containing version information +message VersionResponse { + // Version number + string version = 1; + + // Common error information + Error error = 2; +} diff --git a/protos/market_book.proto b/protos/market_book.proto new file mode 100644 index 0000000..2f4429a --- /dev/null +++ b/protos/market_book.proto @@ -0,0 +1,66 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; + +// Market book entry structure +message BookInfo { + int32 type = 1; // Order type (buy/sell) + double price = 2; // Price + double volume = 3; // Volume +} + +// Request for subscribing to market book +message MarketBookAddRequest { + string symbol = 1; // Symbol name +} + +// Response for market book subscription +message MarketBookAddResponse { + bool success = 1; // Subscription success status + Error error = 2; // Error information if any +} + +// Request for getting market book data +message MarketBookGetRequest { + string symbol = 1; // Symbol name +} + +// Response for getting market book data +message MarketBookGetResponse { + repeated BookInfo book = 1; // Market depth entries + Error error = 2; // Error information if any +} + +// Request for unsubscribing from market book +message MarketBookReleaseRequest { + string symbol = 1; // Symbol name +} + +// Response for market book unsubscription +message MarketBookReleaseResponse { + bool success = 1; // Unsubscription success status + Error error = 2; // Error information if any +} + +// Service definition for Market Book operations +service MarketBookService { + // Subscribe to market depth updates + rpc AddMarketBook(MarketBookAddRequest) returns (MarketBookAddResponse); + + // Get current market depth data + rpc GetMarketBook(MarketBookGetRequest) returns (MarketBookGetResponse); + + // Unsubscribe from market depth updates + rpc ReleaseMarketBook(MarketBookReleaseRequest) returns (MarketBookReleaseResponse); +} + +// ORDER_TYPE enumeration for market book +enum BOOK_TYPE { + BOOK_TYPE_UNSPECIFIED = 0; + BOOK_TYPE_SELL = 1; // Sell order (offer) + BOOK_TYPE_BUY = 2; // Buy order (bid) + BOOK_TYPE_SELL_MARKET = 3; // Sell order by Market + BOOK_TYPE_BUY_MARKET = 4; // Buy order by Market +} \ No newline at end of file diff --git a/protos/market_data.proto b/protos/market_data.proto new file mode 100644 index 0000000..d028d75 --- /dev/null +++ b/protos/market_data.proto @@ -0,0 +1,163 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; +import "google/protobuf/timestamp.proto"; + +// Rate data structure +message Rate { + google.protobuf.Timestamp time = 1; + double open = 2; + double high = 3; + double low = 4; + double close = 5; + int64 tick_volume = 6; + int32 spread = 7; + int64 real_volume = 8; +} + +// Tick data structure +message Tick { + google.protobuf.Timestamp time = 1; + double bid = 2; + double ask = 3; + double last = 4; + uint64 volume = 5; + int64 time_msc = 6; + uint32 flags = 7; + double volume_real = 8; +} + +// Request for copy_rates_from +message CopyRatesFromRequest { + string symbol = 1; // Symbol name + int32 timeframe = 2; // Timeframe from TIMEFRAME enum + google.protobuf.Timestamp date_from = 3; // Initial bar date + int32 count = 4; // Number of bars to get +} + +// Response for copy_rates_from +message CopyRatesFromResponse { + repeated Rate rates = 1; + Error error = 2; +} + +// Request for copy_rates_from_pos +message CopyRatesFromPosRequest { + string symbol = 1; // Symbol name + int32 timeframe = 2; // Timeframe from TIMEFRAME enum + int32 start_pos = 3; // Initial bar index + int32 count = 4; // Number of bars to get +} + +// Response for copy_rates_from_pos +message CopyRatesFromPosResponse { + repeated Rate rates = 1; + Error error = 2; +} + +// Request for copy_rates_range +message CopyRatesRangeRequest { + string symbol = 1; // Symbol name + int32 timeframe = 2; // Timeframe from TIMEFRAME enum + google.protobuf.Timestamp date_from = 3; // Start date + google.protobuf.Timestamp date_to = 4; // End date +} + +// Response for copy_rates_range +message CopyRatesRangeResponse { + repeated Rate rates = 1; + Error error = 2; +} + +// Request for copy_ticks_from +message CopyTicksFromRequest { + string symbol = 1; // Symbol name + google.protobuf.Timestamp date_from = 2; // Start date + int32 count = 3; // Number of ticks to get + int32 flags = 4; // Flags defining type of requested ticks +} + +// Response for copy_ticks_from +message CopyTicksFromResponse { + repeated Tick ticks = 1; + Error error = 2; +} + +// Request for copy_ticks_range +message CopyTicksRangeRequest { + string symbol = 1; // Symbol name + google.protobuf.Timestamp date_from = 2; // Start date + google.protobuf.Timestamp date_to = 3; // End date + int32 flags = 4; // Flags defining type of requested ticks +} + +// Response for copy_ticks_range +message CopyTicksRangeResponse { + repeated Tick ticks = 1; + Error error = 2; +} + +// Service definition for Market Data +service MarketDataService { + // Get bars from specified date + rpc CopyRatesFrom(CopyRatesFromRequest) returns (CopyRatesFromResponse); + + // Get bars from specified position + rpc CopyRatesFromPos(CopyRatesFromPosRequest) returns (CopyRatesFromPosResponse); + + // Get bars for specified date range + rpc CopyRatesRange(CopyRatesRangeRequest) returns (CopyRatesRangeResponse); + + // Get ticks from specified date + rpc CopyTicksFrom(CopyTicksFromRequest) returns (CopyTicksFromResponse); + + // Get ticks for specified date range + rpc CopyTicksRange(CopyTicksRangeRequest) returns (CopyTicksRangeResponse); +} + +// TIMEFRAME enumeration +enum TIMEFRAME { + TIMEFRAME_UNSPECIFIED = 0; + TIMEFRAME_M1 = 1; + TIMEFRAME_M2 = 2; + TIMEFRAME_M3 = 3; + TIMEFRAME_M4 = 4; + TIMEFRAME_M5 = 5; + TIMEFRAME_M6 = 6; + TIMEFRAME_M10 = 10; + TIMEFRAME_M12 = 12; + TIMEFRAME_M15 = 15; + TIMEFRAME_M20 = 20; + TIMEFRAME_M30 = 30; + TIMEFRAME_H1 = 16385; + TIMEFRAME_H2 = 16386; + TIMEFRAME_H3 = 16387; + TIMEFRAME_H4 = 16388; + TIMEFRAME_H6 = 16390; + TIMEFRAME_H8 = 16392; + TIMEFRAME_H12 = 16396; + TIMEFRAME_D1 = 16408; + TIMEFRAME_W1 = 32769; + TIMEFRAME_MN1 = 49153; +} + +// COPY_TICKS enumeration +enum COPY_TICKS { + COPY_TICKS_UNSPECIFIED = 0; + COPY_TICKS_ALL = 1; // all ticks + COPY_TICKS_INFO = 2; // ticks with Bid and/or Ask changes + COPY_TICKS_TRADE = 4; // ticks with changes in Last and Volume +} + +// TICK_FLAG enumeration +enum TICK_FLAG { + TICK_FLAG_UNSPECIFIED = 0; + TICK_FLAG_BID = 2; // Bid price changed + TICK_FLAG_ASK = 4; // Ask price changed + TICK_FLAG_LAST = 8; // Last price changed + TICK_FLAG_VOLUME = 16; // Volume changed + TICK_FLAG_BUY = 32; // Buy price + TICK_FLAG_SELL = 64; // Sell price +} \ No newline at end of file diff --git a/protos/order.proto b/protos/order.proto index b13ce54..1450bba 100644 --- a/protos/order.proto +++ b/protos/order.proto @@ -2,118 +2,60 @@ syntax = "proto3"; package metatrader.v1; -import "google/protobuf/timestamp.proto"; import "common.proto"; +import "google/protobuf/timestamp.proto"; -// Service definition for order operations -service OrderService { - // Get orders based on different filter criteria - rpc GetOrders(GetOrdersRequest) returns (GetOrdersResponse) {} -} - -// Request message for getting orders -message GetOrdersRequest { - oneof filter { - string symbol = 1; // Filter by specific symbol - string group = 2; // Filter by group pattern (e.g., "*GBP*") - int64 ticket = 3; // Filter by specific ticket number - } -} - -// Response message containing orders -message GetOrdersResponse { - repeated Order orders = 1; - optional Error error = 2; +// Request for getting orders +message OrdersGetRequest { + // Optional filtering parameters + optional string symbol = 1; // Specific symbol name + optional string group = 2; // Group filter for symbols + optional int64 ticket = 3; // Specific order ticket } -// Order details +// Single Order details using primitive types message Order { - // Integer properties int64 ticket = 1; google.protobuf.Timestamp time_setup = 2; - google.protobuf.Timestamp time_expiration = 3; + int64 time_setup_msc = 3; google.protobuf.Timestamp time_done = 4; - int64 time_setup_msc = 5; - int64 time_done_msc = 6; - OrderType type = 7; - OrderState state = 8; - OrderTypeTime type_time = 9; - OrderTypeFilling type_filling = 10; - int64 magic = 11; - OrderReason reason = 12; - int64 position_id = 13; - int64 position_by_id = 14; - - // Double properties - double volume_initial = 15; - double volume_current = 16; - double price_open = 17; - double sl = 18; // Stop Loss - double tp = 19; // Take Profit - double price_current = 20; - double price_stoplimit = 21; - - // String properties - string symbol = 22; - string comment = 23; - string external_id = 24; -} - -// Order type enumeration -enum OrderType { - ORDER_TYPE_UNSPECIFIED = 0; - ORDER_TYPE_BUY = 1; // Market Buy order - ORDER_TYPE_SELL = 2; // Market Sell order - ORDER_TYPE_BUY_LIMIT = 3; // Buy Limit pending order - ORDER_TYPE_SELL_LIMIT = 4; // Sell Limit pending order - ORDER_TYPE_BUY_STOP = 5; // Buy Stop pending order - ORDER_TYPE_SELL_STOP = 6; // Sell Stop pending order - ORDER_TYPE_BUY_STOP_LIMIT = 7; // Buy Stop Limit pending order - ORDER_TYPE_SELL_STOP_LIMIT = 8; // Sell Stop Limit pending order - ORDER_TYPE_CLOSE_BY = 9; // Close by opposite position + int64 time_done_msc = 5; + google.protobuf.Timestamp time_expiration = 6; + int32 type = 7; + int32 type_time = 8; + int32 type_filling = 9; + int32 state = 10; + int32 magic = 11; + double volume_current = 12; + double price_open = 13; + double stop_loss = 14; + double take_profit = 15; + double price_current = 16; + string symbol = 17; + string comment = 18; + string external_id = 19; +} + +// Response for getting orders +message OrdersGetResponse { + repeated Order orders = 1; + Error error = 2; } -// Order state enumeration -enum OrderState { - ORDER_STATE_UNSPECIFIED = 0; - ORDER_STATE_STARTED = 1; // Order checked, but not yet accepted - ORDER_STATE_PLACED = 2; // Order accepted - ORDER_STATE_CANCELED = 3; // Order canceled by client - ORDER_STATE_PARTIAL = 4; // Order partially executed - ORDER_STATE_FILLED = 5; // Order fully executed - ORDER_STATE_REJECTED = 6; // Order rejected - ORDER_STATE_EXPIRED = 7; // Order expired - ORDER_STATE_REQUEST_ADD = 8; // Order is being registered - ORDER_STATE_REQUEST_MODIFY = 9; // Order is being modified - ORDER_STATE_REQUEST_CANCEL = 10; // Order is being deleted -} +// Request for getting total number of orders +message OrdersTotalRequest {} -// Order type time enumeration -enum OrderTypeTime { - ORDER_TIME_UNSPECIFIED = 0; - ORDER_TIME_GTC = 1; // Good till cancel - ORDER_TIME_DAY = 2; // Good till current trade day - ORDER_TIME_SPECIFIED = 3; // Good till expired - ORDER_TIME_SPECIFIED_DAY = 4; // Good till specified day +// Response for total number of orders +message OrdersTotalResponse { + int32 total = 1; + Error error = 2; } -// Order type filling enumeration -enum OrderTypeFilling { - ORDER_FILLING_UNSPECIFIED = 0; - ORDER_FILLING_FOK = 1; // Fill or Kill - ORDER_FILLING_IOC = 2; // Immediate or Cancel - ORDER_FILLING_BOC = 3; // Book or Cancel - ORDER_FILLING_RETURN = 4; // Return -} +// Service definition for Orders +service OrdersService { + // Get active orders with optional filtering + rpc GetOrders(OrdersGetRequest) returns (OrdersGetResponse); -// Order reason enumeration -enum OrderReason { - ORDER_REASON_UNSPECIFIED = 0; - ORDER_REASON_CLIENT = 1; // From desktop terminal - ORDER_REASON_MOBILE = 2; // From mobile application - ORDER_REASON_WEB = 3; // From web platform - ORDER_REASON_EXPERT = 4; // From MQL5 program - ORDER_REASON_SL = 5; // Stop Loss activation - ORDER_REASON_TP = 6; // Take Profit activation - ORDER_REASON_SO = 7; // Stop Out event + // Get total number of active orders + rpc GetOrdersTotal(OrdersTotalRequest) returns (OrdersTotalResponse); } \ No newline at end of file diff --git a/protos/order_calc.proto b/protos/order_calc.proto new file mode 100644 index 0000000..4d9a0c8 --- /dev/null +++ b/protos/order_calc.proto @@ -0,0 +1,43 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; + +// Request for calculating margin +message OrderCalcMarginRequest { + int32 action = 1; // Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL) + string symbol = 2; // Symbol name + double volume = 3; // Volume + double price = 4; // Open price +} + +// Response for margin calculation +message OrderCalcMarginResponse { + double margin = 1; // Calculated margin value + Error error = 2; // Error information if any +} + +// Request for calculating profit +message OrderCalcProfitRequest { + int32 action = 1; // Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL) + string symbol = 2; // Symbol name + double volume = 3; // Volume + double price_open = 4; // Open price + double price_close = 5;// Close price +} + +// Response for profit calculation +message OrderCalcProfitResponse { + double profit = 1; // Calculated profit value + Error error = 2; // Error information if any +} + +// Service definition for Order Calculations +service OrderCalcService { + // Calculate margin required for a trading operation + rpc CalcMargin(OrderCalcMarginRequest) returns (OrderCalcMarginResponse); + + // Calculate potential profit for a trading operation + rpc CalcProfit(OrderCalcProfitRequest) returns (OrderCalcProfitResponse); +} \ No newline at end of file diff --git a/protos/order_check.proto b/protos/order_check.proto new file mode 100644 index 0000000..6896882 --- /dev/null +++ b/protos/order_check.proto @@ -0,0 +1,36 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; +import "trade.proto"; + +// Response for order check operation +message OrderCheckResult { + int32 retcode = 1; // Operation return code + double balance = 2; // Balance value after execution + double equity = 3; // Equity value after execution + double profit = 4; // Floating profit value + double margin = 5; // Margin requirements + double margin_free = 6; // Free margin after execution + double margin_level = 7; // Margin level after execution + string comment = 8; // Comment on check result + TradeRequest request = 9; // Original trade request +} + +// Request for checking an order +message OrderCheckRequest { + TradeRequest trade_request = 1; +} + +// Response for order check operation +message OrderCheckResponse { + OrderCheckResult check_result = 1; + Error error = 2; +} + +// Service definition for Order Checking +service OrderCheckService { + // Check if an order can be executed + rpc CheckOrder(OrderCheckRequest) returns (OrderCheckResponse); +} \ No newline at end of file diff --git a/protos/position.proto b/protos/position.proto index b705ded..19db23c 100644 --- a/protos/position.proto +++ b/protos/position.proto @@ -2,64 +2,56 @@ syntax = "proto3"; package metatrader.v1; -import "google/protobuf/timestamp.proto"; import "common.proto"; +import "google/protobuf/timestamp.proto"; -// Service definition for position operations -service PositionService { - // Get positions based on different filter criteria - rpc GetPositions(GetPositionsRequest) returns (GetPositionsResponse) {} -} - -// Request message for getting positions -message GetPositionsRequest { - oneof filter { - string symbol = 1; // Filter by specific symbol - string group = 2; // Filter by group pattern (e.g., "*USD*") - int64 ticket = 3; // Filter by specific ticket number - } -} - -// Response message containing positions -message GetPositionsResponse { - repeated Position positions = 1; - optional Error error = 2; +// Request for getting positions +message PositionsGetRequest { + // Optional filtering parameters + optional string symbol = 1; // Specific symbol name + optional string group = 2; // Group filter for symbols + optional int64 ticket = 3; // Specific position ticket } -// Position details +// Single Position details using primitive types message Position { int64 ticket = 1; - google.protobuf.Timestamp time = 2; - TradeType type = 3; + string symbol = 2; + int32 type = 3; int32 magic = 4; int64 identifier = 5; - TradeReason reason = 6; + int32 reason = 6; double volume = 7; double price_open = 8; - double sl = 9; // Stop Loss - double tp = 10; // Take Profit + double stop_loss = 9; + double take_profit = 10; double price_current = 11; double swap = 12; double profit = 13; - string symbol = 14; - string comment = 15; + string comment = 14; + google.protobuf.Timestamp time = 15; +} + +// Response for getting positions +message PositionsGetResponse { + repeated Position positions = 1; + Error error = 2; } -// Trade type enumeration -enum TradeType { - TRADE_TYPE_UNSPECIFIED = 0; - TRADE_TYPE_SELL = 1; - TRADE_TYPE_BUY = 2; +// Request for getting total number of positions +message PositionsTotalRequest {} + +// Response for total number of positions +message PositionsTotalResponse { + int32 total = 1; + Error error = 2; } -// Trade reason enumeration -enum TradeReason { - TRADE_REASON_UNSPECIFIED = 0; - TRADE_REASON_CLIENT = 1; - TRADE_REASON_MOBILE = 2; - TRADE_REASON_WEB = 3; - TRADE_REASON_EXPERT = 4; - TRADE_REASON_SL = 5; // Stop Loss - TRADE_REASON_TP = 6; // Take Profit - TRADE_REASON_SO = 7; // Stop Out +// Service definition for Positions +service PositionsService { + // Get open positions with optional filtering + rpc GetPositions(PositionsGetRequest) returns (PositionsGetResponse); + + // Get total number of open positions + rpc GetPositionsTotal(PositionsTotalRequest) returns (PositionsTotalResponse); } \ No newline at end of file diff --git a/protos/symbol_info.proto b/protos/symbol_info.proto new file mode 100644 index 0000000..483bfc8 --- /dev/null +++ b/protos/symbol_info.proto @@ -0,0 +1,132 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; +import "google/protobuf/timestamp.proto"; + +// Symbol Information Message +message SymbolInfo { + // Boolean Properties + bool custom = 1; + bool select = 2; + bool visible = 3; + bool spread_float = 4; + bool margin_hedged_use_leg = 5; + + // Integer Properties + int32 chart_mode = 10; + int32 session_deals = 11; + int32 session_buy_orders = 12; + int32 session_sell_orders = 13; + int32 volume = 14; + int32 volumehigh = 15; + int32 volumelow = 16; + int32 digits = 17; + int32 spread = 18; + int32 ticks_bookdepth = 19; + int32 trade_calc_mode = 20; + int32 trade_mode = 21; + int32 trade_stops_level = 22; + int32 trade_freeze_level = 23; + int32 trade_exemode = 24; + int32 swap_mode = 25; + int32 swap_rollover3days = 26; + int32 expiration_mode = 27; + int32 filling_mode = 28; + int32 order_mode = 29; + int32 order_gtc_mode = 30; + int32 option_mode = 31; + int32 option_right = 32; + + // Timestamp Properties + google.protobuf.Timestamp time = 40; + google.protobuf.Timestamp start_time = 41; + google.protobuf.Timestamp expiration_time = 42; + + // Double Properties + double bid = 50; + double bidhigh = 51; + double bidlow = 52; + double ask = 53; + double askhigh = 54; + double asklow = 55; + double last = 56; + double lasthigh = 57; + double lastlow = 58; + double volume_real = 59; + double volumehigh_real = 60; + double volumelow_real = 61; + double option_strike = 62; + double point = 63; + double trade_tick_value = 64; + double trade_tick_value_profit = 65; + double trade_tick_value_loss = 66; + double trade_tick_size = 67; + double trade_contract_size = 68; + double trade_accrued_interest = 69; + double trade_face_value = 70; + double trade_liquidity_rate = 71; + double volume_min = 72; + double volume_max = 73; + double volume_step = 74; + double volume_limit = 75; + double swap_long = 76; + double swap_short = 77; + double margin_initial = 78; + double margin_maintenance = 79; + double session_volume = 80; + double session_turnover = 81; + double session_interest = 82; + double session_buy_orders_volume = 83; + double session_sell_orders_volume = 84; + double session_open = 85; + double session_close = 86; + double session_aw = 87; + double session_price_settlement = 88; + double session_price_limit_min = 89; + double session_price_limit_max = 90; + double margin_hedged = 91; + double price_change = 92; + double price_volatility = 93; + double price_theoretical = 94; + double price_greeks_delta = 95; + double price_greeks_theta = 96; + double price_greeks_gamma = 97; + double price_greeks_vega = 98; + double price_greeks_rho = 99; + double price_greeks_omega = 100; + double price_sensitivity = 101; + + // String Properties + string basis = 110; + string category = 111; + string currency_base = 112; + string currency_profit = 113; + string currency_margin = 114; + string bank = 115; + string description = 116; + string exchange = 117; + string formula = 118; + string isin = 119; + string name = 120; + string page = 121; + string path = 122; +} + +// Request for Symbol Information +message SymbolInfoRequest { + string symbol = 1; // Financial instrument name +} + +// Response for Symbol Information +message SymbolInfoResponse { + SymbolInfo symbol_info = 1; + Error error = 2; +} + +// Service definition for Symbol Information +service SymbolInfoService { + // Get information about a specific financial instrument + rpc GetSymbolInfo(SymbolInfoRequest) returns (SymbolInfoResponse); +} \ No newline at end of file diff --git a/protos/symbol_info_tick.proto b/protos/symbol_info_tick.proto new file mode 100644 index 0000000..1cc810d --- /dev/null +++ b/protos/symbol_info_tick.proto @@ -0,0 +1,50 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; +import "google/protobuf/timestamp.proto"; + +// Tick Information Message +message SymbolInfoTick { + // Timestamp in seconds + google.protobuf.Timestamp time = 1; + + // Bid price + double bid = 2; + + // Ask price + double ask = 3; + + // Last trade price + double last = 4; + + // Volume (integer) + int32 volume = 5; + + // Timestamp in milliseconds + int64 time_msc = 6; + + // Flags + int32 flags = 7; + + // Volume as a real number + double volume_real = 8; +} + +// Request for Symbol Tick Information +message SymbolInfoTickRequest { + string symbol = 1; // Financial instrument name +} + +// Response for Symbol Tick Information +message SymbolInfoTickResponse { + SymbolInfoTick tick = 1; + Error error = 2; +} + +// Service definition for Symbol Tick Information +service SymbolInfoTickService { + // Get the last tick for a specific financial instrument + rpc GetSymbolInfoTick(SymbolInfoTickRequest) returns (SymbolInfoTickResponse); +} \ No newline at end of file diff --git a/protos/symbols.proto b/protos/symbols.proto new file mode 100644 index 0000000..fa7912c --- /dev/null +++ b/protos/symbols.proto @@ -0,0 +1,62 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; + +// Service for working with symbols +service SymbolsService { + // Get the number of all financial instruments + rpc GetSymbolsTotal(SymbolsTotalRequest) returns (SymbolsTotalResponse) {} + + // Get all financial instruments + rpc GetSymbols(SymbolsGetRequest) returns (SymbolsGetResponse) {} + + // Select a symbol in the Market Watch window + rpc SelectSymbol(SymbolSelectRequest) returns (SymbolSelectResponse) {} +} + +// Request for getting total number of symbols +message SymbolsTotalRequest {} + +// Response containing total number of symbols +message SymbolsTotalResponse { + // Total number of symbols + int32 total = 1; + + // Common error information + Error error = 2; +} + +// Request for getting symbols +message SymbolsGetRequest { + // Optional group filter + string group = 1; +} + +// Response containing symbols information +message SymbolsGetResponse { + // List of symbol names + repeated string symbols = 1; + + // Common error information + Error error = 2; +} + +// Request for selecting a symbol +message SymbolSelectRequest { + // Symbol name + string symbol = 1; + + // Selection flag + bool enable = 2; +} + +// Response for symbol selection +message SymbolSelectResponse { + // Success flag + bool success = 1; + + // Common error information + Error error = 2; +} \ No newline at end of file diff --git a/protos/terminal.proto b/protos/terminal.proto new file mode 100644 index 0000000..4b1bc08 --- /dev/null +++ b/protos/terminal.proto @@ -0,0 +1,86 @@ +syntax = "proto3"; + +package metatrader.v1; + +import "common.proto"; + +// Service for getting terminal information +service TerminalInfoService { + // Get MetaTrader 5 terminal information + rpc GetTerminalInfo(TerminalInfoRequest) returns (TerminalInfoResponse) {} +} + +// Request for getting terminal information +message TerminalInfoRequest {} + +// Response containing terminal information +message TerminalInfoResponse { + // Community account flag + bool community_account = 1; + + // Connection to MQL5.community status + bool community_connection = 2; + + // Connection to a trade server status + bool connected = 3; + + // Permission to use DLL + bool dlls_allowed = 4; + + // Permission to trade + bool trade_allowed = 5; + + // Permission to use trading API + bool tradeapi_disabled = 6; + + // Permission to send emails using SMTP-server and login specified in the terminal settings + bool email_enabled = 7; + + // Permission to send reports using FTP-server and login specified in the terminal settings + bool ftp_enabled = 8; + + // Permission to send notifications to smartphone + bool notifications_enabled = 9; + + // Flag indicating presence of MetaQuotes ID data to send Push notifications + bool mqid = 10; + + // Client terminal build number + int32 build = 11; + + // Maximum bars count in charts + int32 maxbars = 12; + + // Code page of the language installed in the client terminal + int32 codepage = 13; + + // Last known value of ping to trade server in microseconds + int32 ping_last = 14; + + // Community balance + float community_balance = 15; + + // Connection data retransmission percentage + float retransmission = 16; + + // Company name + string company = 17; + + // Terminal name + string name = 18; + + // Language of terminal + string language = 19; + + // Folder from which the terminal is started + string path = 20; + + // Folder in which terminal data are stored + string data_path = 21; + + // Common path for all terminals installed on a computer + string commondata_path = 22; + + // Common error information + Error error = 23; +} \ No newline at end of file diff --git a/protos/trade.proto b/protos/trade.proto index fe69756..da28f16 100644 --- a/protos/trade.proto +++ b/protos/trade.proto @@ -1,125 +1,113 @@ syntax = "proto3"; -package trading_system; +package metatrader.v1; +import "common.proto"; import "google/protobuf/timestamp.proto"; -// Trade Request Actions Enumeration -enum TradeRequestAction { - TRADE_ACTION_DEAL = 0; // Open/Close position - TRADE_ACTION_PENDING = 1; // Place pending order - TRADE_ACTION_MODIFY = 2; // Modify existing order - TRADE_ACTION_REMOVE = 3; // Remove pending order - TRADE_ACTION_SLTP = 4; // Modify Stop Loss/Take Profit -} - -// Trade Request Structure +// Trade Request Message message TradeRequest { - // Core Request Properties - TradeRequestAction action = 1; // Trade operation type - uint64 magic = 2; // Expert Advisor ID (magic number) - uint64 order = 3; // Order ticket (for modification) - string symbol = 4; // Trade symbol - double volume = 5; // Requested volume in lots - double price = 6; // Execution/Order price - double stoplimit = 7; // StopLimit level for pending orders - double sl = 8; // Stop Loss price - double tp = 9; // Take Profit price - uint64 deviation = 10; // Maximum price deviation in points - - // Order Specifics - OrderType type = 11; // Order type (buy/sell/limit/stop) - OrderTypeFilling type_filling = 12; // Order execution type - OrderTypeTime type_time = 13; // Order expiration type - google.protobuf.Timestamp expiration = 14; // Order expiration time - string comment = 15; // Order comment - - // Position Management - uint64 position = 16; // Position ticket for modification/closure - uint64 position_by = 17; // Ticket of opposite position for closing - - // Enumerations (reusing from previous contract) - enum OrderType { - ORDER_TYPE_BUY = 0; - ORDER_TYPE_SELL = 1; - ORDER_TYPE_BUY_LIMIT = 2; - ORDER_TYPE_SELL_LIMIT = 3; - ORDER_TYPE_BUY_STOP = 4; - ORDER_TYPE_SELL_STOP = 5; - ORDER_TYPE_BUY_STOP_LIMIT = 6; - ORDER_TYPE_SELL_STOP_LIMIT = 7; - ORDER_TYPE_CLOSE_BY = 8; - } - - enum OrderTypeFilling { - ORDER_FILLING_FOK = 0; // Fill or Kill - ORDER_FILLING_IOC = 1; // Immediate or Cancel - ORDER_FILLING_BOC = 2; // Book or Cancel - ORDER_FILLING_RETURN = 3; // Return remaining volume - } - - enum OrderTypeTime { - ORDER_TIME_GTC = 0; // Good till cancel - ORDER_TIME_DAY = 1; // Good till current trade day - ORDER_TIME_SPECIFIED = 2; // Good till expired - ORDER_TIME_SPECIFIED_DAY = 3; // Good till specified day - } -} + // Trading operation type + int32 action = 1; + + // EA ID for analytical handling + int32 magic = 2; + + // Order ticket (for modifying orders) + optional int64 order = 3; + + // Trading instrument symbol + optional string symbol = 4; + + // Requested volume in lots + double volume = 5; + + // Execution price + optional double price = 6; + + // Stop limit price + optional double stoplimit = 7; + + // Stop Loss price + optional double sl = 8; + + // Take Profit price + optional double tp = 9; + + // Maximum acceptable price deviation in points + int32 deviation = 10; + + // Order type + int32 type = 11; + + // Order filling type + int32 type_filling = 12; -// Trade Request Result Structure -message TradeRequestResult { - uint32 retcode = 1; // Operation return code - uint64 deal = 2; // Deal ticket - uint64 order = 3; // Order ticket - double volume = 4; // Executed volume - double price = 5; // Execution price - double bid = 6; // Current Bid price - double ask = 7; // Current Ask price - string comment = 8; // Broker comment to operation - uint32 request_id = 9; // Request ID set by the terminal during the dispatch - int32 retcode_external = 10; // Return code of an external trading system - - // Detailed status - enum ResultStatus { - SUCCESS = 0; - PARTIAL_FILL = 1; - ERROR = 2; - REJECTED = 3; - CANCELLED = 4; - } - - ResultStatus status = 11; - string error_description = 12; + // Order time type + int32 type_time = 13; + + // Expiration time for pending orders + optional google.protobuf.Timestamp expiration = 14; + + // Order comment + optional string comment = 15; + + // Position ticket for closing/modifying + optional int64 position = 16; + + // Opposite position ticket + optional int64 position_by = 17; } -// Trade Management Service -service TradeManagementService { - // Open a new position or place a pending order - rpc SendTradeRequest(TradeRequest) returns (TradeRequestResult) {} +// Trade Result Message +message TradeResult { + // Return code of the operation + int32 retcode = 1; + + // Deal ticket + int64 deal = 2; + + // Order ticket + int64 order = 3; + + // Executed volume + double volume = 4; + + // Execution price + double price = 5; + + // Bid price + double bid = 6; + + // Ask price + double ask = 7; + + // Comment on the operation + string comment = 8; + + // Request ID + int64 request_id = 9; + + // External return code + int32 retcode_external = 10; + + // Original trade request + TradeRequest request = 11; } -// Advanced Filtering for Trade Requests -message TradeRequestFilter { - repeated TradeRequestAction actions = 1; - string symbol = 2; - google.protobuf.Timestamp from_date = 3; - google.protobuf.Timestamp to_date = 4; - uint64 magic_number = 5; - bool include_closed = 6; - double min_volume = 7; - double max_volume = 8; +// Request for sending an order +message OrderSendRequest { + TradeRequest trade_request = 1; } -// Trade History Request -message TradeHistoryRequest { - TradeRequestFilter filter = 1; - uint32 page_size = 2; - uint32 page_token = 3; +// Response for order send operation +message OrderSendResponse { + TradeResult trade_result = 1; + Error error = 2; } -// Trade History Response -message TradeHistoryResponse { - repeated TradeRequest trade_requests = 1; - uint32 total_count = 2; - uint32 next_page_token = 3; +// Service definition for Order Sending +service OrderSendService { + // Send a trading order + rpc SendOrder(OrderSendRequest) returns (OrderSendResponse); } \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c355007 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +grpcio==1.68.1 +grpcio-tools==1.68.1 +protobuf==5.29.2 +pytz~=2024.2 +mt5-grpc-proto==0.1.0 \ No newline at end of file diff --git a/start_server_under_wine.sh b/start_server_under_wine.sh index fdc94f8..5f2d807 100644 --- a/start_server_under_wine.sh +++ b/start_server_under_wine.sh @@ -1 +1,6 @@ -wine cmd /C "cd Z:\Users\user\dev\Metatrader5-RPC-server && set PYTHONPATH=Z:\Users\user\dev\Metatrader5-RPC-server && python main.py" \ No newline at end of file + + +# For development purposes, you can run the server under wine for the Linux or MacOS. +# Change the path to the project directory and the path to the python interpreter if necessary. + +wine cmd /C "cd Z:\Users\user\dev\Metatrader5-gRPC-server\mt5_grpc_server && python -m mt5_grpc_server.grpc_server" \ No newline at end of file