diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..9117132 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,44 @@ +name: Publish distributions + +on: + push: + branches: + - '*' + tags: + - v* + +jobs: + build-and-publish: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install --upgrade setuptools + python -m pip install poetry + python -m pip install twine + python -m poetry install + + - name: Build and publish to Test PyPI + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.TEST_PYPI }} + run: | + python -m poetry build + twine upload --skip-existing --repository-url https://test.pypi.org/legacy/ dist/* + + - name: Publish to PyPI (if it's a new tag) + if: github.ref == 'refs/heads/master' + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + run: | + python -m poetry build + twine upload dist/* diff --git a/.gitignore b/.gitignore index 7ade0b4..ee79715 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -# Project exclude paths -/tensor-venv/ +.env +*.pyc \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..50001c9 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,23 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + language_version: python3 + + + +- repo: https://github.com/psf/black + rev: 23.11.0 + hooks: + - id: black + args: [--safe, --line-length=120] + +- repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + args: [--profile=black] diff --git a/README.md b/README.md index cb51ca8..10772a9 100644 --- a/README.md +++ b/README.md @@ -1,142 +1,21 @@ # Mql5-Python-Integration -I am working on a **new project** based on this one! -This new project is splitted into modules. -You can find the release of the **first module** on the links below. +## Project Overview -Keep in mind that **some features** that you can find on Mql5-Python-Integration **are not presented yet** on the new one, -but **I will add the features** and many new ones. +**Current Version: v0.6.0** +Welcome to the Mql5-Python-Integration project! This project facilitates the integration between MetaTrader 5 (Mql5) and Python, allowing for efficient algorithmic trading strategies. -My page: -https://joaopeuko.github.io/ +## Project Update: Changes in Progress -Pypi of the first module: -https://pypi.org/project/metatrader5EasyT/ +🚧 **Work in Progress: v0.6.0** +This project is currently undergoing significant changes and improvements. The latest version is v0.6.0, and various enhancements are being made to provide a more robust and user-friendly experience. -GitHub project -https://github.com/Joaopeuko/metatrader5EasyT +📌 **Previous Version: v0.5.0** +To access the code for the previous version, you can check it out at [v0.5.0](https://github.com/Joaopeuko/Mql5-Python-Integration/releases/tag/v0.5.0). -Project documentation -https://joaopeuko.github.io/metatrader5EasyT/ +## Table of Contents -## Patron who makes the difference! - -Help me make it possible. Be my [Patreon](https://www.patreon.com/joaopeuko). - -## Introduction - -I created this library because the development of an Expert Advisor in MQL5 can be complicated,while, in python, the same task flows better. - -I believe that the main advantage of using python, instead of MQL5, to develop an expert advisor is the possibility to implement machine learning, deep learning, and reinforcement learning to your code in a faster way. However, I still don´t cover these. - -I find that using the “MetaTrader module for integration with Python” is straightforward; yet, there is space for improvement. - -Thus, I created this library, aiming to transform the experience of Expert Advisor Creation. Python is a versatile language; it counts with a wide range of useful libraries, which, in turn, allows the implementation of diverse ideas, easily. - - -## Installation - - -[pip](https://www.mql5.com/en/docs/integration/python_metatrader5) install MetaTrader5 - -```python -pip install MetaTrader5 -``` - - -## Expert Advisor - -There is an expert advisor example for each different technology in the Expert Advisor folder. - -### Simple Example - -[example.py](https://github.com/Joaopeuko/Mql5-Python-Integration/blob/master/examples_of_expert_advisor/example.py) - - It uses just the MetaTrader5 library in the implementation. - -### Socket Example - -[example_sockets_connection.py](https://github.com/Joaopeuko/Mql5-Python-Integration/blob/master/examples_of_expert_advisor/example_sockets_connection.py) - - -The “MetaTrader module for integration with Python” enables a wide range of possibilities; still, there is space for improvement. For instance, it lacks a connection to indicators. - -That problem can be solved: -- Using Python indicators libraries that already exist through the internet. -- Re-creating all the indicators -- Creating a connection with MetaTrader5, asking for some indicators. - -This example uses a socket connection to simplify the usage of indicators and it shows how easy it is to implement. You can find the indicator connection file [here](https://github.com/Joaopeuko/Mql5-Python-Integration/blob/master/include/indicator_connector.py). - -To be able to use socket connection you need the client-side and the server-side to allow the communication. - -The python code, that is used in this example, is the server-side that waits for the client-side to send the indicator result asked for. - -The python code that is used in this example is the server-side that waits for the client-side to send the indicator result asked for. In order to use the client-side, it is possible to code it in MQL-language or to use the ones that I already created: - - - [here](https://www.mql5.com/en/market/product/57574) - Free - 5 Indicators - - [here](https://www.mql5.com/en/market/product/58056) - Not Free - [38](https://www.mql5.com/en/docs/indicators) Indicators (5 from free indicators plus 33 new ones). The iCustom is not implemented. - -To use the indicator in the expert advisor, you can call it providing the symbol name, all the other variables have pre-configured values. It always uses a time_frame for 1 minute. - -[example_sockets_connection.py](https://github.com/Joaopeuko/Mql5-Python-Integration/blob/master/examples_of_expert_advisor/example_sockets_connection.py) - -```python -from include.indicator_connector import Indicator - -indicator = Indicator() - -moving_average = indicator.moving_average(symbol='PETR4') # Brazilian Stock -``` - -You can check [this](https://github.com/Joaopeuko/Mql5-Python-Integration/blob/master/include/indicator_connector.py) file to find some tips when calling an indicator, for example, on how to change the method or the applied price. - -```python - def moving_average(self, - symbol, - time_frame=1, - period=20, - start_position=0, # Change it if you want past values, zero is the most recent. - # method: - # 0 - MODE_SMA - # 1 - MODE_EMA - # 2 - MODE_SMMA - # 3 - MODE_LWMA - method=0, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): -``` - -When using the indicators, please use try and except; sometimes the result can return "None." - -[example_sockets_connection.py](https://github.com/Joaopeuko/Mql5-Python-Integration/blob/master/examples_of_expert_advisor/example_sockets_connection.py) - -```python -from include.indicator_connector import Indicator - -indicator = Indicator() - -while True: - try: - moving_average = indicator.moving_average(symbol='PETR4') # Brazilian Stock - except TypeError: - pass -``` - -The indicator result is a dictionary. -```python -print(moving_average) -{'symbol': 'PETR4', 'time_frame': 1, 'period': 50, 'start_position': 0, 'method': 0, 'applied_price': 0, 'moving_average_result': 23.103} - -print(moving_average['moving_average_result']) -23.103 - -``` +- [Mql5-Python-Integration](#mql5-python-integration) + - [Project Update: Changes in Progress](#project-update-changes-in-progress) + - [Table of Contents](#table-of-contents) diff --git a/example.py b/example.py new file mode 100644 index 0000000..70fd866 --- /dev/null +++ b/example.py @@ -0,0 +1,45 @@ +from mqpy.src.rates import Rates +from mqpy.src.tick import Tick +from mqpy.src.trade import Trade + +# Initialize the trading strategy +trade = Trade( + expert_name="Example", + version=0.1, + symbol="EURUSD", + magic_number=567, + lot=1.0, + stop_loss=25, + emergency_stop_loss=300, + take_profit=25, + emergency_take_profit=300, + start_time="9:15", + finishing_time="17:30", + ending_time="17:50", + fee=0.5, +) + +# Main trading loop +time = 0 +while True: + # Fetch tick and rates data + tick = Tick(trade.symbol) + rates = Rates(trade.symbol, 1, 0, 1) + + # Check for new tick + if tick.time_msc != time: + buy_signal = tick.last > rates.open + sell_signal = tick.last < rates.open + + # Execute trading positions based on signals + trade.open_position(buy_signal, sell_signal, "Example Advisor") + + time = tick.time_msc + + # Check if it's the end of the trading day + if trade.days_end(): + trade.close_position("End of the trading day reached.") + break + +print("Finishing the program.") +print("Program finished.") diff --git a/examples_of_expert_advisor/example.py b/examples_of_expert_advisor/example.py deleted file mode 100644 index 58e2b35..0000000 --- a/examples_of_expert_advisor/example.py +++ /dev/null @@ -1,40 +0,0 @@ -from include.trade import Trade -from include.tick import Tick -from include.rates import Rates - - -trade = Trade('Example', # Expert name - 0.1, # Expert Version - 'WING21', # symbol - 567, # Magic number - 1.0, # lot, it is a floating point. - 25, # stop loss - 300, # emergency stop loss - 25, # take profit - 300, # emergency take profit - '9:15', # It is allowed to trade after that hour. Do not use zeros, like: 09 - '17:30', # It is not allowed to trade after that hour but let open all the position already opened. - '17:50', # It closes all the position opened. Do not use zeros, like: 09 - 0.5, # average fee - ) - -time = 0 -while True: - - tick = Tick(trade.symbol) - rates = Rates(trade.symbol, 1, 0, 1) - - if tick.time_msc != time: - buy = (tick.last > rates.open) - sell = (tick.last < rates.open) - - trade.open_position(buy, sell, 'Example Advisor') - - time = tick.time_msc - - if trade.days_end(): - trade.close_position('End of the trading day reached.') - break - -print('Finishing the program.') -print('Program finished.') diff --git a/include/book.py b/include/book.py deleted file mode 100644 index 1601c5c..0000000 --- a/include/book.py +++ /dev/null @@ -1,18 +0,0 @@ -import MetaTrader5 as Mt5 - - -class Book: - def __init__(self, - symbol): - self.symbol = symbol - if Mt5.market_book_add(self.symbol): - print(f'The symbol {self.symbol} was successfully added to market book.') - - else: - print(f'Some thing happened adding {self.symbol} to market book, error: {Mt5.last_error()}') - - def get(self): - return Mt5.market_book_get(self.symbol) - - def release(self): - return Mt5.market_book_release(self.symbol) diff --git a/include/indicator_connector.py b/include/indicator_connector.py deleted file mode 100644 index c08f3cb..0000000 --- a/include/indicator_connector.py +++ /dev/null @@ -1,1642 +0,0 @@ -import socket -import json - - -# To be able to use it you need the MQL5 Service to send the data, it is possible to found it here: -# -------------------------------------------------------------------- # -# Free: -# https://www.mql5.com/en/market/product/57574 -# - Bollinger Bands -# - MACD -# - Moving Average -# - OBV On Balance Volume -# - Stochastic -# -# -------------------------------------------------------------------- # -# -# -------------------------------------------------------------------- # -# $30.00 Dollars per 3 month. ($10.00/month): -# https://www.mql5.com/en/market/product/58056 -# - Accelerator Oscillator -# - Accumulation/Distribution -# - Adaptive Moving Average -# - Alligator -# - Average Directional Movement Index -# - Average Directional Movement Index Wilder -# - Average True Range -# - Awesome Oscillator -# - Bollinger Bands - Free -# - Bears Power -# - Bulls Power -# - Chaikin Oscillator -# - Commodity Channel Index -# - DeMarker -# - Double Exponential Moving Average -# - Envelops -# - Force Index -# - Fractal Adaptive Moving Average -# - Fractals -# - Gator Oscillator -# - Ichimoku Kinko Hyo -# - MACD - Free -# - Market Facilitation Index -# - Momentum -# - Money Flow Index -# - Moving Average - Free -# - Moving Average of Oscillator -# - OBV On Balance Volume - Free -# - Parabolic SAR -# - Relative Strength Index -# - Relative Vigor Index -# - Standard Deviation -# - Stochastic - Free -# - Triple Exponential Average -# - Triple Exponential Moving Average -# - Variable Index Dynamic Average -# - Volumes -# - Williams' Percent Range -# -# -------------------------------------------------------------------- # - -class Indicator: - def __init__(self, - address='localhost', - port=9090, - listen=1): - - self.address = address - self.port = port - self.listen = listen - self.location = (address, port) - - self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.s.bind((self.address, self.port)) - self.s.listen(self.listen) - - # -------------------------------------------------------------------- # - # Paid - - def accelerator_oscillator(self, - symbol, - time_frame=1, - start_position=0): # Change it if you want past values, zero is the most recent. - - try: - client_socket, address = self.s.accept() - message = (f"accelerator_oscillator," - f"{symbol}," - f"{time_frame}," - f"{start_position}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def accumulation_distribution(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - # applied_volume: - # 0 - VOLUME_TICK - # 1 - VOLUME_REAL - applied_volume=0): - - try: - client_socket, address = self.s.accept() - message = (f"accumulation_distribution," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{applied_volume}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def adaptive_moving_average(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ama_period=9, - fast_ma_period=2, - slow_ma_period=30, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=4 - ): - - try: - client_socket, address = self.s.accept() - message = (f"adaptive_moving_average," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ama_period}," - f"{fast_ma_period}," - f"{slow_ma_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def alligator(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - jaw_period=13, - teeth_period=8, - lips_period=5, - # method: - # 0 - MODE_SMA - # 1 - MODE_EMA - # 2 - MODE_SMMA - # 3 - MODE_LWMA - ma_method=2, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=4 - ): - - try: - client_socket, address = self.s.accept() - message = (f"alligator," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{jaw_period}," - f"{teeth_period}," - f"{lips_period}," - f"{ma_method}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def average_directional_index(self, - symbol, - time_frame=1, - period=14, - start_position=0): # Change it if you want past values, zero is the most recent. - - try: - client_socket, address = self.s.accept() - message = (f"average_directional_index," - f"{symbol}," - f"{time_frame}," - f"{period}," - f"{start_position}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def average_directional_index_wilder(self, - symbol, - time_frame=1, - period=14, - start_position=0): # Change it if you want past values, zero is the most - # recent. - - try: - client_socket, address = self.s.accept() - message = (f"average_directional_index_wilder," - f"{symbol}," - f"{time_frame}," - f"{period}," - f"{start_position}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def average_true_range(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=14): - - try: - client_socket, address = self.s.accept() - message = (f"average_true_range," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def awesome_oscillator(self, - symbol, - time_frame=1, - start_position=0): # Change it if you want past values, zero is the most recent. - - try: - client_socket, address = self.s.accept() - message = (f"awesome_oscillator," - f"{symbol}," - f"{time_frame}," - f"{start_position}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Free - def bollinger_bands(self, - symbol, - time_frame=1, - period=20, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_shift=0, - deviation=2.000, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - - try: - client_socket, address = self.s.accept() - message = (f"bollinger_bands," - f"{symbol}," - f"{time_frame}," - f"{period}," - f"{start_position}," - f"{ma_shift}," - f"{deviation}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def bears_power(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=13): - try: - client_socket, address = self.s.accept() - message = (f"bears_power," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def bulls_power(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=13): - try: - client_socket, address = self.s.accept() - message = (f"bulls_power," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def chaikin_oscillator(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - fast_ma_period=3, - slow_ma_period=10, - # method: - # 0 - MODE_SMA - # 1 - MODE_EMA - # 2 - MODE_SMMA - # 3 - MODE_LWMA - ma_method=1, - # applied_volume: - # 0 - VOLUME_TICK - # 1 - VOLUME_REAL - applied_volume=0): - try: - client_socket, address = self.s.accept() - message = (f"chaikin_oscillator," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{fast_ma_period}," - f"{slow_ma_period}," - f"{ma_method}," - f"{applied_volume}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def commodity_channel_index(self, - symbol, - time_frame=1, - start_position=1, # Change it if you want past values, zero is the most recent. - ma_period=14, - # For this Indicator, the applied price is shifted. - # applied_price: - # 1 - PRICE_CLOSE - # 2 - PRICE_OPEN - # 3 - PRICE_HIGH - # 4 - PRICE_LOW - # 5 - PRICE_MEDIAN - # 6 - PRICE_TYPICAL - # 7 - PRICE_WEIGHTED - applied_price=0): - try: - client_socket, address = self.s.accept() - message = (f"commodity_channel_index," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def demarker(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - period=14): - try: - client_socket, address = self.s.accept() - message = (f"demarker," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{period}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def double_exponential_moving_average(self, - symbol, - time_frame=1, - start_position=0, - # Change it if you want past values, zero is the most recent. - ma_period=14, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - try: - client_socket, address = self.s.accept() - message = (f"double_exponential_moving_average," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def envelopes(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=14, - # method: - # 0 - MODE_SMA - # 1 - MODE_EMA - # 2 - MODE_SMMA - # 3 - MODE_LWMA - ma_method=0, - # For this Indicator, the applied price is shifted. - # applied_price: - # 1 - PRICE_CLOSE - # 2 - PRICE_OPEN - # 3 - PRICE_HIGH - # 4 - PRICE_LOW - # 5 - PRICE_MEDIAN - # 6 - PRICE_TYPICAL - # 7 - PRICE_WEIGHTED - applied_price=1, - deviation=0.100): - try: - client_socket, address = self.s.accept() - message = (f"envelopes," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{ma_method}," - f"{applied_price}," - f"{deviation}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - def force_index(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=13, - # method: - # 0 - MODE_SMA - # 1 - MODE_EMA - # 2 - MODE_SMMA - # 3 - MODE_LWMA - ma_method=0, - # applied_volume: - # 0 - VOLUME_TICK - # 1 - VOLUME_REAL - applied_volume=0): - try: - client_socket, address = self.s.accept() - message = (f"force_index," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{ma_method}," - f"{applied_volume}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def fractal_adaptive_moving_average(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=14, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0 - ): - try: - client_socket, address = self.s.accept() - message = (f"fractal_adaptive_moving_average," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def fractals(self, - symbol, - time_frame=1, - start_position=0): # Change it if you want past values, zero is the most recent. - - try: - client_socket, address = self.s.accept() - message = (f"fractals," - f"{symbol}," - f"{time_frame}," - f"{start_position}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - # https://www.mql5.com/en/forum/41357 - def gator_oscillator(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - jaw_period=13, - jaw_shift=8, - teeth_period=8, - teeth_shift=5, - lips_period=5, - lips_shift=3, - # method: - # 0 - MODE_SMA - # 1 - MODE_EMA - # 2 - MODE_SMMA - # 3 - MODE_LWMA - ma_method=2, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=4 - ): - try: - client_socket, address = self.s.accept() - message = (f"gator_oscillator," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{jaw_period}," - f"{jaw_shift}," - f"{teeth_period}," - f"{teeth_shift}," - f"{lips_period}," - f"{lips_shift}," - f"{ma_method}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def ichimoku_kinko_hyo(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - tenkan_sen=9, - kijun_sen=26, - senkou_span_b=52): - try: - client_socket, address = self.s.accept() - message = (f"ichimoku_kinko_hyo," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{tenkan_sen}," - f"{kijun_sen}," - f"{senkou_span_b}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Free - def macd(self, - symbol, - time_frame=1, - fast_ema_period=12, - slow_ema_period=26, - signal_period=9, - start_position=0, # Change it if you want past values, zero is the most recent. - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - - try: - client_socket, address = self.s.accept() - message = (f"macd," - f"{symbol}," - f"{time_frame}," - f"{fast_ema_period}," - f"{slow_ema_period}," - f"{signal_period}," - f"{start_position}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def market_facilitation_index(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - # applied_volume: - # 0 - VOLUME_TICK - # 1 - VOLUME_REAL - applied_volume=0): - try: - client_socket, address = self.s.accept() - message = (f"market_facilitation_index," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{applied_volume}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def momentum(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - mom_period=14, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - try: - client_socket, address = self.s.accept() - message = (f"momentum," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{mom_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def money_flow_index(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=14, - # applied_volume: - # 0 - VOLUME_TICK - # 1 - VOLUME_REAL - applied_volume=0): - try: - client_socket, address = self.s.accept() - message = (f"money_flow_index," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{applied_volume}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Free - def moving_average(self, - symbol, - time_frame=1, - period=20, - start_position=0, # Change it if you want past values, zero is the most recent. - # method: - # 0 - MODE_SMA - # 1 - MODE_EMA - # 2 - MODE_SMMA - # 3 - MODE_LWMA - method=0, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - - try: - client_socket, address = self.s.accept() - message = (f"moving_average," - f"{symbol}," - f"{time_frame}," - f"{period}," - f"{start_position}," - f"{method}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def moving_average_of_oscillator(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - fast_ema_period=12, - slow_ema_period=26, - macd_sma_period=9, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - try: - client_socket, address = self.s.accept() - message = (f"moving_average_of_oscillator," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{fast_ema_period}," - f"{slow_ema_period}," - f"{macd_sma_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Free - def obv(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - # applied_volume: - # 0 - VOLUME_TICK - # 1 - VOLUME_REAL - applied_volume=0): - - try: - client_socket, address = self.s.accept() - message = (f"obv," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{applied_volume}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def parabolic_sar(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - step=0.02, - maximum=0.2): - try: - client_socket, address = self.s.accept() - message = (f"parabolic_sar," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{step}," - f"{maximum}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def relative_strength_index(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=14, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - try: - client_socket, address = self.s.accept() - message = (f"relative_strength_index," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def relative_vigor_index(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=10): - try: - client_socket, address = self.s.accept() - message = (f"relative_vigor_index," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def standard_deviation(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - ma_period=20, - # method: - # 0 - MODE_SMA - # 1 - MODE_EMA - # 2 - MODE_SMMA - # 3 - MODE_LWMA - ma_method=0, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - try: - client_socket, address = self.s.accept() - message = (f"standard_deviation," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{ma_method}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Free - def stochastic(self, - symbol, - time_frame=1, - k_period=5, - d_period=3, - slowing=3, - start_position=0, # Change it if you want past values, zero is the most recent. - # method: - # 0 - MODE_SMA - # 1 - MODE_EMA - # 2 - MODE_SMMA - # 3 - MODE_LWMA - method=0, - # applied_price - # 0 - STO_LOWHIGH - # 1 - STO_CLOSECLOSE - applied_price=0): - - try: - client_socket, address = self.s.accept() - message = (f"stochastic," - f"{symbol}," - f"{time_frame}," - f"{k_period}," - f"{d_period}," - f"{slowing}," - f"{start_position}," - f"{method}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def triple_exponential_ma_oscillator(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, - # zero is the most recent. - ma_period=14, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - try: - client_socket, address = self.s.accept() - message = (f"triple_exponential_ma_oscillator," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def triple_exponential_moving_average(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, - # zero is the most recent. - ma_period=14, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - try: - client_socket, address = self.s.accept() - message = (f"triple_exponential_moving_average," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{ma_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def variable_index_dynamic_average(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - cmo_period=9, - ema_period=12, - # applied_price: - # 0 - PRICE_CLOSE - # 1 - PRICE_OPEN - # 2 - PRICE_HIGH - # 3 - PRICE_LOW - # 4 - PRICE_MEDIAN - # 5 - PRICE_TYPICAL - # 6 - PRICE_WEIGHTED - applied_price=0): - try: - client_socket, address = self.s.accept() - message = (f"variable_index_dynamic_average," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{cmo_period}," - f"{ema_period}," - f"{applied_price}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def volumes(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - # applied_volume: - # 0 - VOLUME_TICK - # 1 - VOLUME_REAL - applied_volume=0): - try: - client_socket, address = self.s.accept() - message = (f"volumes," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{applied_volume}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass - - # -------------------------------------------------------------------- # - # Paid - - def williams_percent_range(self, - symbol, - time_frame=1, - start_position=0, # Change it if you want past values, zero is the most recent. - calc_period=14): - try: - client_socket, address = self.s.accept() - message = (f"williams_percent_range," - f"{symbol}," - f"{time_frame}," - f"{start_position}," - f"{calc_period}") - - client_socket.send(bytes(message, 'utf-8')) - data = client_socket.recv(1024) - - result = data.decode('utf-8') - try: - return json.loads(result) - - except ValueError: - print('Connection lost to MQL5 Service') - pass - - except ConnectionResetError: - pass - - except ConnectionAbortedError: - pass diff --git a/include/rates.py b/include/rates.py deleted file mode 100644 index 81f0480..0000000 --- a/include/rates.py +++ /dev/null @@ -1,14 +0,0 @@ -import MetaTrader5 as Mt5 - - -class Rates: - def __init__(self, symbol, time_frame, start_pos, period): - - self.time = Mt5.copy_rates_from_pos(symbol, time_frame, start_pos, period)['time'] - self.open = Mt5.copy_rates_from_pos(symbol, time_frame, start_pos, period)['open'] - self.high = Mt5.copy_rates_from_pos(symbol, time_frame, start_pos, period)['high'] - self.low = Mt5.copy_rates_from_pos(symbol, time_frame, start_pos, period)['low'] - self.close = Mt5.copy_rates_from_pos(symbol, time_frame, start_pos, period)['close'] - self.tick_volume = Mt5.copy_rates_from_pos(symbol, time_frame, start_pos, period)['tick_volume'] - self.spread = Mt5.copy_rates_from_pos(symbol, time_frame, start_pos, period)['spread'] - self.real_volume = Mt5.copy_rates_from_pos(symbol, time_frame, start_pos, period)['real_volume'] diff --git a/include/tick.py b/include/tick.py deleted file mode 100644 index 68b63c5..0000000 --- a/include/tick.py +++ /dev/null @@ -1,14 +0,0 @@ -import MetaTrader5 as Mt5 - - -class Tick: - def __init__(self, symbol): - - self.time = Mt5.symbol_info_tick(symbol).time - self.bid = Mt5.symbol_info_tick(symbol).bid - self.ask = Mt5.symbol_info_tick(symbol).ask - self.last = Mt5.symbol_info_tick(symbol).last - self.volume = Mt5.symbol_info_tick(symbol).volume - self.time_msc = Mt5.symbol_info_tick(symbol).time_msc - self.flags = Mt5.symbol_info_tick(symbol).flags - self.volume_real = Mt5.symbol_info_tick(symbol).volume_real diff --git a/include/trade.py b/include/trade.py deleted file mode 100644 index c5b0aa3..0000000 --- a/include/trade.py +++ /dev/null @@ -1,249 +0,0 @@ -from datetime import datetime, timedelta -import MetaTrader5 as Mt5 - - -class Trade: - def __init__(self, - expert_name, - version, - symbol, - magic_number, - lot: float, - stop_loss, # It calls a functions that tries to close the deal, it is the stop you want. - emergency_stop_loss, # It set stop on chart as a protection - # if something went wrong with the stop_loss. - take_profit, # The same of stop_loss but for profit. - emergency_take_profit, # The same of emergency_stop_loss but for gain - start_time='9:15', # It is the hour and minutes that the expert advisor are able to start to run. - finishing_time='17:30', # No new position can be opened after that time. - ending_time='17:50', # If there is a position opened it will be closed. - fee=0.0, - ): - - self.expert_name = expert_name - self.version = version - self.symbol = symbol - self.magic_number = magic_number - self.lot = lot - self.stop_loss = stop_loss - self.emergency_stop_loss = emergency_stop_loss - self.take_profit = take_profit - self.emergency_take_profit = emergency_take_profit - self.start_time_hour, self.start_time_minutes = start_time.split(':') - self.finishing_time_hour, self.finishing_time_minutes = finishing_time.split(':') - self.ending_time_hour, self.ending_time_minutes = ending_time.split(':') - self.fee = fee - - self.loss_deals = 0 - self.profit_deals = 0 - self.total_deals = 0 - self.balance = 0.0 - - self.ticket = 0 - - print('\nInitializing the basics.') - self.initialize() - self.select_symbol() - self.prepare_symbol() - self.sl_tp_steps = Mt5.symbol_info(self.symbol).trade_tick_size / Mt5.symbol_info(self.symbol).point - print('Initialization successfully completed.') - - print() - self.summary() - print('Running') - print() - - def initialize(self): - if not Mt5.initialize(): - print('Initialization failed, check internet connection. You must have Meta Trader 5 installed.') - Mt5.shutdown() - - else: - print( - f'You are running the {self.expert_name} expert advisor,' - f' version {self.version}, on symbol {self.symbol}.') - - def select_symbol(self): - Mt5.symbol_select(self.symbol, True) - - def prepare_symbol(self): - # Prepare the symbol to open positions - symbol_info = Mt5.symbol_info(self.symbol) - if symbol_info is None: - print(f'It was not possible to find {self.symbol}') - Mt5.shutdown() - print('Turned off') - quit() - - if not symbol_info.visible: - print(f'The {self.symbol} is not visible, needed to be switched on.') - if not Mt5.symbol_select(self.symbol, True): - print(f'The expert advisor {self.expert_name} failed in select the symbol {self.symbol}, turning off.') - Mt5.shutdown() - print('Turned off') - quit() - - def summary(self): - print( - f'Summary:\n' - f'ExpertAdvisor name: {self.expert_name}\n' - f'ExpertAdvisor version: {self.version}\n' - f'Running on symbol: {self.symbol}\n' - f'MagicNumber: {self.magic_number}\n' - f'Number of lot(s): {self.lot}\n' - f'StopLoss: {self.stop_loss}\n' - f'TakeProfit: {self.take_profit}\n' - f'Emergency StopLoss: {self.emergency_stop_loss}\n' - f'Emergency TakeProfit: {self.emergency_take_profit}\n' - f'Start trading time: {self.start_time_hour}:{self.start_time_minutes}\n' - f'Finishing trading time: {self.finishing_time_hour}:{self.finishing_time_minutes}\n' - f'Closing position after: {self.ending_time_hour}:{self.ending_time_minutes}\n' - f'Average fee per trading: {self.fee}\n' - f'StopLoss & TakeProfit Steps: {self.sl_tp_steps}\n' - ) - - def statistics(self): - print(f'Total of deals: {self.total_deals}, {self.profit_deals} gain, {self.loss_deals} loss.') - print(f'Balance: {self.balance}, fee: {self.total_deals * self.fee}, final balance:' - f' {self.balance - (self.total_deals * self.fee)}.') - if self.total_deals != 0: - print(f'Accuracy: {round((self.profit_deals / self.total_deals) * 100, 2)}%.\n') - - # It is to open a Buy position. - def open_buy_position(self, comment=""): - point = Mt5.symbol_info(self.symbol).point - price = Mt5.symbol_info_tick(self.symbol).ask - - self.ticket = (Mt5.positions_get()[0].ticket if len(Mt5.positions_get()) == 1 else 0) - - request = { - "action": Mt5.TRADE_ACTION_DEAL, - "symbol": self.symbol, - "volume": self.lot, - "type": Mt5.ORDER_TYPE_BUY, - "price": price, - "sl": price - self.emergency_stop_loss * point, - "tp": price + self.emergency_take_profit * point, - "deviation": 5, - "magic": self.magic_number, - "comment": str(comment), - "type_time": Mt5.ORDER_TIME_GTC, - "type_filling": Mt5.ORDER_FILLING_RETURN, - "position": (Mt5.positions_get()[0].ticket if len(Mt5.positions_get()) == 1 else 0) - } - result = Mt5.order_send(request) - self.request_result(price, result) - - # It is to open a Sell position. - def open_sell_position(self, comment=""): - point = Mt5.symbol_info(self.symbol).point - price = Mt5.symbol_info_tick(self.symbol).bid - - self.ticket = (Mt5.positions_get()[0].ticket if len(Mt5.positions_get()) == 1 else 0) - - request = { - "action": Mt5.TRADE_ACTION_DEAL, - "symbol": self.symbol, - "volume": self.lot, - "type": Mt5.ORDER_TYPE_SELL, - "price": price, - "sl": price + self.emergency_stop_loss * point, - "tp": price - self.emergency_take_profit * point, - "deviation": 5, - "magic": self.magic_number, - "comment": str(comment), - "type_time": Mt5.ORDER_TIME_GTC, - "type_filling": Mt5.ORDER_FILLING_RETURN, - "position": (Mt5.positions_get()[0].ticket if len(Mt5.positions_get()) == 1 else 0) - } - result = Mt5.order_send(request) - self.request_result(price, result) - - def request_result(self, price, result): - # Send a trading request - # Check the execution result - print(f'Order sent: {self.symbol}, {self.lot} lot(s), at {price}.') - if result.retcode != Mt5.TRADE_RETCODE_DONE: - print(f'Something went wrong while retrieving ret_code, error: {result.retcode}') - - # Print the result - if result.retcode == Mt5.TRADE_RETCODE_DONE: - if len(Mt5.positions_get(symbol=self.symbol)) == 1: - order_type = 'Buy' if Mt5.positions_get(symbol=self.symbol)[0].type == 0 else 'Sell' - print(order_type, 'Position Opened:', result.price) - else: - print(f'Position Closed: {result.price}') - - def open_position(self, buy, sell, comment=""): - if (len(Mt5.positions_get(symbol=self.symbol)) == 0) and self.trading_time(): - if buy and not sell: - self.open_buy_position(comment) - self.total_deals += 1 - if sell and not buy: - self.open_sell_position(comment) - self.total_deals += 1 - - self.stop_and_gain(comment) - - if self.days_end(): - print('It is the end of trading the day.') - print('Closing all positions.') - self.close_position(comment) - self.summary() - - def close_position(self, comment=""): - # buy (0) and sell(1) - if len(Mt5.positions_get(symbol=self.symbol)) == 1: - - if Mt5.positions_get(symbol=self.symbol)[0].type == 0: # if Buy - self.open_sell_position(comment) - - elif Mt5.positions_get(symbol=self.symbol)[0].type == 1: # if Sell - self.open_buy_position(comment) - - def stop_and_gain(self, comment=""): - if len(Mt5.positions_get()) == 1: - - points = (Mt5.positions_get()[0].profit * - Mt5.symbol_info(self.symbol).trade_tick_size / - Mt5.symbol_info(self.symbol).trade_tick_value) / \ - Mt5.positions_get()[0].volume - - if points / Mt5.symbol_info(self.symbol).point >= self.take_profit: - self.profit_deals += 1 - self.close_position(comment) - print(f'Take profit reached. (' - f'{Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[-1].profit}' - f')\n') - if Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[-1].symbol == \ - self.symbol: - self.balance += (Mt5.history_deals_get((datetime.today() - timedelta(days=1)), - datetime.now())[-1].profit) - self.statistics() - - elif ((points / Mt5.symbol_info(self.symbol).point) * -1) >= self.stop_loss: - self.loss_deals += 1 - self.close_position(comment) - print(f'Stop loss reached. (' - f'{Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[-1].profit}' - f')\n') - if Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[-1].symbol == \ - self.symbol: - self.balance += (Mt5.history_deals_get((datetime.today() - timedelta(days=1)), - datetime.now())[-1].profit) - self.statistics() - - def days_end(self): - if datetime.now().hour >= int(self.ending_time_hour) and datetime.now().minute >= int(self.ending_time_minutes): - return True - - def trading_time(self): - if int(self.start_time_hour) < datetime.now().hour < int(self.finishing_time_hour): - return True - elif datetime.now().hour == int(self.start_time_hour): - if datetime.now().minute >= int(self.start_time_minutes): - return True - elif datetime.now().hour == int(self.finishing_time_hour): - if datetime.now().minute < int(self.finishing_time_minutes): - return True - return False diff --git a/include/utilities.py b/include/utilities.py deleted file mode 100644 index a2fa590..0000000 --- a/include/utilities.py +++ /dev/null @@ -1,44 +0,0 @@ -from datetime import datetime -import MetaTrader5 as Mt5 - - -class Utilities: - def __init__(self): - - # Variables for minutes_counter - self.__minutes_counter = 0 - self.__counter_flag = True - self.__allowed_to_trade = True - self.__allow_to_count = False - self.__recent_trade = False - - # This function will count the amount of minutes after some trade end. - # You can use it as a condition to allow trades to happen. - def minutes_counter_after_trade(self, symbol, count_until): - if len(Mt5.positions_get(symbol=symbol)) == 1: - self.__recent_trade = True - - if len(Mt5.positions_get(symbol=symbol)) != 1 and self.__recent_trade: - if not self.__allow_to_count: - self.__allow_to_count = True - self.__allowed_to_trade = False - self.__recent_trade = False - - if datetime.now().second == 0 and self.__counter_flag and self.__allow_to_count: - print(f"Your Expert Advisor will be allowed to trade in {count_until-self.__minutes_counter} minutes.") - self.__minutes_counter += 1 - self.__counter_flag = False - - if datetime.now().second == 59: - self.__counter_flag = True - - if self.__minutes_counter == count_until: - print(f"Your Expert Advisor is allowed to trade.\n") - self.__minutes_counter = 0 - self.__counter_flag = True - self.__allow_to_count = False - self.__allowed_to_trade = True - - return self.__allowed_to_trade - - diff --git a/mqpy/src/__init__.py b/mqpy/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mqpy/src/book.py b/mqpy/src/book.py new file mode 100644 index 0000000..44bb66c --- /dev/null +++ b/mqpy/src/book.py @@ -0,0 +1,41 @@ +from typing import Optional + +import MetaTrader5 as Mt5 + + +class Book: + """Represents a market book for a financial instrument.""" + + def __init__(self, symbol: str) -> None: + """ + Initialize the Book object. + + Args: + symbol (str): The financial instrument symbol. + + Returns: + None + """ + self.symbol: str = symbol + if Mt5.market_book_add(self.symbol): + print(f"The symbol {self.symbol} was successfully added to the market book.") + else: + print(f"Error adding {self.symbol} to the market book. Error: {Mt5.last_error()}") + + def get(self) -> Optional[dict]: + """ + Get the market book for the financial instrument. + + Returns: + Optional[dict]: A dictionary representing the market book, or None if unsuccessful. + """ + return Mt5.market_book_get(self.symbol) + + def release(self) -> bool: + """ + Release the market book for the financial instrument. + + Returns: + bool: True if successful, False otherwise. + """ + return Mt5.market_book_release(self.symbol) diff --git a/mqpy/src/indicator_connector.py b/mqpy/src/indicator_connector.py new file mode 100644 index 0000000..d74ee80 --- /dev/null +++ b/mqpy/src/indicator_connector.py @@ -0,0 +1,1627 @@ +import json +import socket + +# To be able to use it you need the MQL5 Service to send the data, it is possible to found it here: +# -------------------------------------------------------------------- # +# Free: +# https://www.mql5.com/en/market/product/57574 +# - Bollinger Bands +# - MACD +# - Moving Average +# - OBV On Balance Volume +# - Stochastic +# -------------------------------------------------------------------- # +# https://www.mql5.com/en/market/product/58056 +# - Accelerator Oscillator +# - Accumulation/Distribution +# - Adaptive Moving Average +# - Alligator +# - Average Directional Movement Index +# - Average Directional Movement Index Wilder +# - Average True Range +# - Awesome Oscillator +# - Bollinger Bands - Free +# - Bears Power +# - Bulls Power +# - Chaikin Oscillator +# - Commodity Channel Index +# - DeMarker +# - Double Exponential Moving Average +# - Envelops +# - Force Index +# - Fractal Adaptive Moving Average +# - Fractals +# - Gator Oscillator +# - Ichimoku Kinko Hyo +# - MACD - Free +# - Market Facilitation Index +# - Momentum +# - Money Flow Index +# - Moving Average - Free +# - Moving Average of Oscillator +# - OBV On Balance Volume - Free +# - Parabolic SAR +# - Relative Strength Index +# - Relative Vigor Index +# - Standard Deviation +# - Stochastic - Free +# - Triple Exponential Average +# - Triple Exponential Moving Average +# - Variable Index Dynamic Average +# - Volumes +# - Williams' Percent Range +# +# -------------------------------------------------------------------- # + + +class Indicator: + def __init__(self, address="localhost", port=9090, listen=1): + self.address = address + self.port = port + self.listen = listen + self.location = (address, port) + + self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.s.bind((self.address, self.port)) + self.s.listen(self.listen) + + # -------------------------------------------------------------------- # + + def accelerator_oscillator( + self, symbol, time_frame=1, start_position=0 + ): # Change it if you want past values, zero is the most recent. + try: + client_socket, address = self.s.accept() + message = f"accelerator_oscillator," f"{symbol}," f"{time_frame}," f"{start_position}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def accumulation_distribution( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + # applied_volume: + # 0 - VOLUME_TICK + # 1 - VOLUME_REAL + applied_volume=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"accumulation_distribution," f"{symbol}," f"{time_frame}," f"{start_position}," f"{applied_volume}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def adaptive_moving_average( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ama_period=9, + fast_ma_period=2, + slow_ma_period=30, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=4, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"adaptive_moving_average," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ama_period}," + f"{fast_ma_period}," + f"{slow_ma_period}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def alligator( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + jaw_period=13, + teeth_period=8, + lips_period=5, + # method: + # 0 - MODE_SMA + # 1 - MODE_EMA + # 2 - MODE_SMMA + # 3 - MODE_LWMA + ma_method=2, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=4, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"alligator," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{jaw_period}," + f"{teeth_period}," + f"{lips_period}," + f"{ma_method}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def average_directional_index( + self, symbol, time_frame=1, period=14, start_position=0 + ): # Change it if you want past values, zero is the most recent. + try: + client_socket, address = self.s.accept() + message = f"average_directional_index," f"{symbol}," f"{time_frame}," f"{period}," f"{start_position}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def average_directional_index_wilder( + self, symbol, time_frame=1, period=14, start_position=0 + ): # Change it if you want past values, zero is the most + # recent. + + try: + client_socket, address = self.s.accept() + message = ( + f"average_directional_index_wilder," f"{symbol}," f"{time_frame}," f"{period}," f"{start_position}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def average_true_range( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=14, + ): + try: + client_socket, address = self.s.accept() + message = f"average_true_range," f"{symbol}," f"{time_frame}," f"{start_position}," f"{ma_period}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def awesome_oscillator( + self, symbol, time_frame=1, start_position=0 + ): # Change it if you want past values, zero is the most recent. + try: + client_socket, address = self.s.accept() + message = f"awesome_oscillator," f"{symbol}," f"{time_frame}," f"{start_position}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + # Free + def bollinger_bands( + self, + symbol, + time_frame=1, + period=20, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_shift=0, + deviation=2.000, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"bollinger_bands," + f"{symbol}," + f"{time_frame}," + f"{period}," + f"{start_position}," + f"{ma_shift}," + f"{deviation}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def bears_power( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=13, + ): + try: + client_socket, address = self.s.accept() + message = f"bears_power," f"{symbol}," f"{time_frame}," f"{start_position}," f"{ma_period}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def bulls_power( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=13, + ): + try: + client_socket, address = self.s.accept() + message = f"bulls_power," f"{symbol}," f"{time_frame}," f"{start_position}," f"{ma_period}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def chaikin_oscillator( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + fast_ma_period=3, + slow_ma_period=10, + # method: + # 0 - MODE_SMA + # 1 - MODE_EMA + # 2 - MODE_SMMA + # 3 - MODE_LWMA + ma_method=1, + # applied_volume: + # 0 - VOLUME_TICK + # 1 - VOLUME_REAL + applied_volume=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"chaikin_oscillator," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{fast_ma_period}," + f"{slow_ma_period}," + f"{ma_method}," + f"{applied_volume}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def commodity_channel_index( + self, + symbol, + time_frame=1, + start_position=1, # Change it if you want past values, zero is the most recent. + ma_period=14, + # For this Indicator, the applied price is shifted. + # applied_price: + # 1 - PRICE_CLOSE + # 2 - PRICE_OPEN + # 3 - PRICE_HIGH + # 4 - PRICE_LOW + # 5 - PRICE_MEDIAN + # 6 - PRICE_TYPICAL + # 7 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"commodity_channel_index," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def demarker( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + period=14, + ): + try: + client_socket, address = self.s.accept() + message = f"demarker," f"{symbol}," f"{time_frame}," f"{start_position}," f"{period}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def double_exponential_moving_average( + self, + symbol, + time_frame=1, + start_position=0, + # Change it if you want past values, zero is the most recent. + ma_period=14, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"double_exponential_moving_average," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def envelopes( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=14, + # method: + # 0 - MODE_SMA + # 1 - MODE_EMA + # 2 - MODE_SMMA + # 3 - MODE_LWMA + ma_method=0, + # For this Indicator, the applied price is shifted. + # applied_price: + # 1 - PRICE_CLOSE + # 2 - PRICE_OPEN + # 3 - PRICE_HIGH + # 4 - PRICE_LOW + # 5 - PRICE_MEDIAN + # 6 - PRICE_TYPICAL + # 7 - PRICE_WEIGHTED + applied_price=1, + deviation=0.100, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"envelopes," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{ma_method}," + f"{applied_price}," + f"{deviation}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + def force_index( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=13, + # method: + # 0 - MODE_SMA + # 1 - MODE_EMA + # 2 - MODE_SMMA + # 3 - MODE_LWMA + ma_method=0, + # applied_volume: + # 0 - VOLUME_TICK + # 1 - VOLUME_REAL + applied_volume=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"force_index," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{ma_method}," + f"{applied_volume}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def fractal_adaptive_moving_average( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=14, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"fractal_adaptive_moving_average," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def fractals( + self, symbol, time_frame=1, start_position=0 + ): # Change it if you want past values, zero is the most recent. + try: + client_socket, address = self.s.accept() + message = f"fractals," f"{symbol}," f"{time_frame}," f"{start_position}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + # https://www.mql5.com/en/forum/41357 + def gator_oscillator( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + jaw_period=13, + jaw_shift=8, + teeth_period=8, + teeth_shift=5, + lips_period=5, + lips_shift=3, + # method: + # 0 - MODE_SMA + # 1 - MODE_EMA + # 2 - MODE_SMMA + # 3 - MODE_LWMA + ma_method=2, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=4, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"gator_oscillator," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{jaw_period}," + f"{jaw_shift}," + f"{teeth_period}," + f"{teeth_shift}," + f"{lips_period}," + f"{lips_shift}," + f"{ma_method}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def ichimoku_kinko_hyo( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + tenkan_sen=9, + kijun_sen=26, + senkou_span_b=52, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"ichimoku_kinko_hyo," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{tenkan_sen}," + f"{kijun_sen}," + f"{senkou_span_b}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + # Free + def macd( + self, + symbol, + time_frame=1, + fast_ema_period=12, + slow_ema_period=26, + signal_period=9, + start_position=0, # Change it if you want past values, zero is the most recent. + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"macd," + f"{symbol}," + f"{time_frame}," + f"{fast_ema_period}," + f"{slow_ema_period}," + f"{signal_period}," + f"{start_position}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def market_facilitation_index( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + # applied_volume: + # 0 - VOLUME_TICK + # 1 - VOLUME_REAL + applied_volume=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"market_facilitation_index," f"{symbol}," f"{time_frame}," f"{start_position}," f"{applied_volume}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def momentum( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + mom_period=14, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"momentum," f"{symbol}," f"{time_frame}," f"{start_position}," f"{mom_period}," f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def money_flow_index( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=14, + # applied_volume: + # 0 - VOLUME_TICK + # 1 - VOLUME_REAL + applied_volume=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"money_flow_index," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{applied_volume}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + # Free + def moving_average( + self, + symbol, + time_frame=1, + period=20, + start_position=0, # Change it if you want past values, zero is the most recent. + # method: + # 0 - MODE_SMA + # 1 - MODE_EMA + # 2 - MODE_SMMA + # 3 - MODE_LWMA + method=0, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"moving_average," + f"{symbol}," + f"{time_frame}," + f"{period}," + f"{start_position}," + f"{method}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def moving_average_of_oscillator( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + fast_ema_period=12, + slow_ema_period=26, + macd_sma_period=9, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"moving_average_of_oscillator," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{fast_ema_period}," + f"{slow_ema_period}," + f"{macd_sma_period}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + # Free + def obv( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + # applied_volume: + # 0 - VOLUME_TICK + # 1 - VOLUME_REAL + applied_volume=0, + ): + try: + client_socket, address = self.s.accept() + message = f"obv," f"{symbol}," f"{time_frame}," f"{start_position}," f"{applied_volume}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def parabolic_sar( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + step=0.02, + maximum=0.2, + ): + try: + client_socket, address = self.s.accept() + message = f"parabolic_sar," f"{symbol}," f"{time_frame}," f"{start_position}," f"{step}," f"{maximum}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def relative_strength_index( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=14, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"relative_strength_index," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def relative_vigor_index( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=10, + ): + try: + client_socket, address = self.s.accept() + message = f"relative_vigor_index," f"{symbol}," f"{time_frame}," f"{start_position}," f"{ma_period}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def standard_deviation( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + ma_period=20, + # method: + # 0 - MODE_SMA + # 1 - MODE_EMA + # 2 - MODE_SMMA + # 3 - MODE_LWMA + ma_method=0, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"standard_deviation," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{ma_method}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + # Free + def stochastic( + self, + symbol, + time_frame=1, + k_period=5, + d_period=3, + slowing=3, + start_position=0, # Change it if you want past values, zero is the most recent. + # method: + # 0 - MODE_SMA + # 1 - MODE_EMA + # 2 - MODE_SMMA + # 3 - MODE_LWMA + method=0, + # applied_price + # 0 - STO_LOWHIGH + # 1 - STO_CLOSECLOSE + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"stochastic," + f"{symbol}," + f"{time_frame}," + f"{k_period}," + f"{d_period}," + f"{slowing}," + f"{start_position}," + f"{method}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def triple_exponential_ma_oscillator( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, + # zero is the most recent. + ma_period=14, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"triple_exponential_ma_oscillator," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def triple_exponential_moving_average( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, + # zero is the most recent. + ma_period=14, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"triple_exponential_moving_average," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{ma_period}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def variable_index_dynamic_average( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + cmo_period=9, + ema_period=12, + # applied_price: + # 0 - PRICE_CLOSE + # 1 - PRICE_OPEN + # 2 - PRICE_HIGH + # 3 - PRICE_LOW + # 4 - PRICE_MEDIAN + # 5 - PRICE_TYPICAL + # 6 - PRICE_WEIGHTED + applied_price=0, + ): + try: + client_socket, address = self.s.accept() + message = ( + f"variable_index_dynamic_average," + f"{symbol}," + f"{time_frame}," + f"{start_position}," + f"{cmo_period}," + f"{ema_period}," + f"{applied_price}" + ) + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def volumes( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + # applied_volume: + # 0 - VOLUME_TICK + # 1 - VOLUME_REAL + applied_volume=0, + ): + try: + client_socket, address = self.s.accept() + message = f"volumes," f"{symbol}," f"{time_frame}," f"{start_position}," f"{applied_volume}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass + + # -------------------------------------------------------------------- # + + def williams_percent_range( + self, + symbol, + time_frame=1, + start_position=0, # Change it if you want past values, zero is the most recent. + calc_period=14, + ): + try: + client_socket, address = self.s.accept() + message = f"williams_percent_range," f"{symbol}," f"{time_frame}," f"{start_position}," f"{calc_period}" + + client_socket.send(bytes(message, "utf-8")) + data = client_socket.recv(1024) + + result = data.decode("utf-8") + try: + return json.loads(result) + + except ValueError: + print("Connection lost to MQL5 Service") + pass + + except ConnectionResetError: + pass + + except ConnectionAbortedError: + pass diff --git a/mqpy/src/rates.py b/mqpy/src/rates.py new file mode 100644 index 0000000..c827f5c --- /dev/null +++ b/mqpy/src/rates.py @@ -0,0 +1,80 @@ +from typing import List, Union + +import MetaTrader5 as Mt5 + + +class Rates: + """Represents historical rates data for a financial instrument.""" + + def __init__(self, symbol: str, time_frame: int, start_pos: int, period: int) -> None: + """ + Initializes a Rates object. + + Args: + symbol (str): The financial instrument symbol. + time_frame (int): The time frame of the rates data. + start_pos (int): The starting position for data retrieval. + period (int): The number of rates to retrieve. + + Returns: + None + """ + self._symbol = symbol + try: + rates_data = Mt5.copy_rates_from_pos(self._symbol, time_frame, start_pos, period) + + self._time = rates_data["time"] + self._open = rates_data["open"] + self._high = rates_data["high"] + self._low = rates_data["low"] + self._close = rates_data["close"] + self._tick_volume = rates_data["tick_volume"] + self._spread = rates_data["spread"] + self._real_volume = rates_data["real_volume"] + + # Optionally, you can print statements here for debugging + # print(f"Rates object created for symbol: {self._symbol}") + except Exception as e: + # Optionally, you can print statements here for debugging + # print(f"Failed to create Rates object for symbol {self._symbol}. Error: {e}") + raise + + @property + def time(self) -> List[Union[int, float]]: + """List of timestamps.""" + return self._time + + @property + def open(self) -> List[float]: + """List of open prices.""" + return self._open + + @property + def high(self) -> List[float]: + """List of high prices.""" + return self._high + + @property + def low(self) -> List[float]: + """List of low prices.""" + return self._low + + @property + def close(self) -> List[float]: + """List of close prices.""" + return self._close + + @property + def tick_volume(self) -> List[int]: + """List of tick volumes.""" + return self._tick_volume + + @property + def spread(self) -> List[int]: + """List of spreads.""" + return self._spread + + @property + def real_volume(self) -> List[int]: + """List of real volumes.""" + return self._real_volume diff --git a/mqpy/src/tick.py b/mqpy/src/tick.py new file mode 100644 index 0000000..a1fb5e6 --- /dev/null +++ b/mqpy/src/tick.py @@ -0,0 +1,74 @@ +from typing import Optional + +import MetaTrader5 as Mt5 + + +class Tick: + """Represents real-time tick data for a financial instrument.""" + + def __init__(self, symbol: str) -> None: + """ + Initializes a Tick object. + + Args: + symbol (str): The financial instrument symbol. + + Returns: + None + """ + tick_info = Mt5.symbol_info_tick(symbol) + + self._symbol = symbol + self._time = tick_info.time + self._bid = tick_info.bid + self._ask = tick_info.ask + self._last = tick_info.last + self._volume = tick_info.volume + self._time_msc = tick_info.time_msc + self._flags = tick_info.flags + self._volume_real = tick_info.volume_real + + @property + def symbol(self) -> str: + """The financial instrument symbol.""" + return self._symbol + + @property + def time(self) -> int: + """Timestamp of the tick data.""" + return self._time + + @property + def bid(self) -> float: + """Current bid price.""" + return self._bid + + @property + def ask(self) -> float: + """Current ask price.""" + return self._ask + + @property + def last(self) -> float: + """Last traded price.""" + return self._last + + @property + def volume(self) -> int: + """Tick volume.""" + return self._volume + + @property + def time_msc(self) -> int: + """Timestamp in milliseconds.""" + return self._time_msc + + @property + def flags(self) -> int: + """Flags indicating tick data attributes.""" + return self._flags + + @property + def volume_real(self) -> Optional[float]: + """Real volume (if available).""" + return self._volume_real diff --git a/mqpy/src/trade.py b/mqpy/src/trade.py new file mode 100644 index 0000000..328678b --- /dev/null +++ b/mqpy/src/trade.py @@ -0,0 +1,381 @@ +from datetime import datetime, timedelta + +import MetaTrader5 as Mt5 + + +class Trade: + """ + Represents a trading strategy for a financial instrument. + + Args: + expert_name (str): The name of the expert advisor. + version (str): The version of the expert advisor. + symbol (str): The financial instrument symbol. + magic_number (int): The magic number for identifying trades. + lot (float): The number of lots to trade. + stop_loss (float): The stop loss level. + emergency_stop_loss (float): Emergency stop loss as a protection. + take_profit (float): The take profit level. + emergency_take_profit (float): Emergency take profit for gain. + start_time (str): The time when the expert advisor can start trading. + finishing_time (str): The time until new positions can be opened. + ending_time (str): The time when any remaining position will be closed. + fee (float): The average fee per trading. + """ + + def __init__( + self, + expert_name: str, + version: str, + symbol: str, + magic_number: int, + lot: float, + stop_loss: float, + emergency_stop_loss: float, + take_profit: float, + emergency_take_profit: float, + start_time: str = "9:15", + finishing_time: str = "17:30", + ending_time: str = "17:50", + fee: float = 0.0, + ) -> None: + """ + Initialize the Trade object. + + Returns: + None + """ + self.expert_name: str = expert_name + self.version: str = version + self.symbol: str = symbol + self.magic_number: int = magic_number + self.lot: float = lot + self.stop_loss: float = stop_loss + self.emergency_stop_loss: float = emergency_stop_loss + self.take_profit: float = take_profit + self.emergency_take_profit: float = emergency_take_profit + self.start_time_hour, self.start_time_minutes = start_time.split(":") + self.finishing_time_hour, self.finishing_time_minutes = finishing_time.split(":") + self.ending_time_hour, self.ending_time_minutes = ending_time.split(":") + self.fee: float = fee + + self.loss_deals: int = 0 + self.profit_deals: int = 0 + self.total_deals: int = 0 + self.balance: float = 0.0 + + self.ticket: int = 0 + + print("\nInitializing the basics.") + self.initialize() + self.select_symbol() + self.prepare_symbol() + self.sl_tp_steps: float = Mt5.symbol_info(self.symbol).trade_tick_size / Mt5.symbol_info(self.symbol).point + print("Initialization successfully completed.") + + print() + self.summary() + print("Running") + print() + + def initialize(self) -> None: + """ + Initialize the MetaTrader 5 instance. + + Returns: + None + """ + if not Mt5.initialize(): + print("Initialization failed, check internet connection. You must have Meta Trader 5 installed.") + Mt5.shutdown() + else: + print( + f"You are running the {self.expert_name} expert advisor," + f" version {self.version}, on symbol {self.symbol}." + ) + + def select_symbol(self) -> None: + """ + Select the trading symbol. + + Returns: + None + """ + Mt5.symbol_select(self.symbol, True) + + def prepare_symbol(self) -> None: + """ + Prepare the trading symbol for opening positions. + + Returns: + None + """ + symbol_info = Mt5.symbol_info(self.symbol) + if symbol_info is None: + print(f"It was not possible to find {self.symbol}") + Mt5.shutdown() + print("Turned off") + quit() + + if not symbol_info.visible: + print(f"The {self.symbol} is not visible, needed to be switched on.") + if not Mt5.symbol_select(self.symbol, True): + print(f"The expert advisor {self.expert_name} failed in select the symbol {self.symbol}, turning off.") + Mt5.shutdown() + print("Turned off") + quit() + + def summary(self) -> None: + """ + Print a summary of the expert advisor parameters. + + Returns: + None + """ + print( + f"Summary:\n" + f"ExpertAdvisor name: {self.expert_name}\n" + f"ExpertAdvisor version: {self.version}\n" + f"Running on symbol: {self.symbol}\n" + f"MagicNumber: {self.magic_number}\n" + f"Number of lot(s): {self.lot}\n" + f"StopLoss: {self.stop_loss}\n" + f"TakeProfit: {self.take_profit}\n" + f"Emergency StopLoss: {self.emergency_stop_loss}\n" + f"Emergency TakeProfit: {self.emergency_take_profit}\n" + f"Start trading time: {self.start_time_hour}:{self.start_time_minutes}\n" + f"Finishing trading time: {self.finishing_time_hour}:{self.finishing_time_minutes}\n" + f"Closing position after: {self.ending_time_hour}:{self.ending_time_minutes}\n" + f"Average fee per trading: {self.fee}\n" + f"StopLoss & TakeProfit Steps: {self.sl_tp_steps}\n" + ) + + def statistics(self) -> None: + """ + Print statistics of the expert advisor. + + Returns: + None + """ + print(f"Total of deals: {self.total_deals}, {self.profit_deals} gain, {self.loss_deals} loss.") + print( + f"Balance: {self.balance}, fee: {self.total_deals * self.fee}, final balance:" + f" {self.balance - (self.total_deals * self.fee)}." + ) + if self.total_deals != 0: + print(f"Accuracy: {round((self.profit_deals / self.total_deals) * 100, 2)}%.\n") + + def open_buy_position(self, comment: str = "") -> None: + """ + Open a Buy position. + + Args: + comment (str): A comment for the trade. + + Returns: + None + """ + point = Mt5.symbol_info(self.symbol).point + price = Mt5.symbol_info_tick(self.symbol).ask + + self.ticket = Mt5.positions_get()[0].ticket if len(Mt5.positions_get()) == 1 else 0 + + request = { + "action": Mt5.TRADE_ACTION_DEAL, + "symbol": self.symbol, + "volume": self.lot, + "type": Mt5.ORDER_TYPE_BUY, + "price": price, + "sl": price - self.emergency_stop_loss * point, + "tp": price + self.emergency_take_profit * point, + "deviation": 5, + "magic": self.magic_number, + "comment": str(comment), + "type_time": Mt5.ORDER_TIME_GTC, + "type_filling": Mt5.ORDER_FILLING_RETURN, + "position": (Mt5.positions_get()[0].ticket if len(Mt5.positions_get()) == 1 else 0), + } + result = Mt5.order_send(request) + self.request_result(price, result) + + def open_sell_position(self, comment: str = "") -> None: + """ + Open a Sell position. + + Args: + comment (str): A comment for the trade. + + Returns: + None + """ + point = Mt5.symbol_info(self.symbol).point + price = Mt5.symbol_info_tick(self.symbol).bid + + self.ticket = Mt5.positions_get()[0].ticket if len(Mt5.positions_get()) == 1 else 0 + + request = { + "action": Mt5.TRADE_ACTION_DEAL, + "symbol": self.symbol, + "volume": self.lot, + "type": Mt5.ORDER_TYPE_SELL, + "price": price, + "sl": price + self.emergency_stop_loss * point, + "tp": price - self.emergency_take_profit * point, + "deviation": 5, + "magic": self.magic_number, + "comment": str(comment), + "type_time": Mt5.ORDER_TIME_GTC, + "type_filling": Mt5.ORDER_FILLING_RETURN, + "position": (Mt5.positions_get()[0].ticket if len(Mt5.positions_get()) == 1 else 0), + } + result = Mt5.order_send(request) + self.request_result(price, result) + + def request_result(self, price: float, result) -> None: + """ + Process the result of a trading request. + + Args: + price (float): The price of the trade. + result (Mt5.TradeResult): The result of the trading request. + Returns: + None + """ + # Send a trading request + # Check the execution result + print(f"Order sent: {self.symbol}, {self.lot} lot(s), at {price}.") + if result.retcode != Mt5.TRADE_RETCODE_DONE: + print(f"Something went wrong while retrieving ret_code, error: {result.retcode}") + + # Print the result + if result.retcode == Mt5.TRADE_RETCODE_DONE: + if len(Mt5.positions_get(symbol=self.symbol)) == 1: + order_type = "Buy" if Mt5.positions_get(symbol=self.symbol)[0].type == 0 else "Sell" + print(order_type, "Position Opened:", result.price) + else: + print(f"Position Closed: {result.price}") + + def open_position(self, buy: bool, sell: bool, comment: str = "") -> None: + """ + Open a position based on buy and sell conditions. + + Args: + buy (bool): True if a Buy position should be opened, False otherwise. + sell (bool): True if a Sell position should be opened, False otherwise. + comment (str): A comment for the trade. + + Returns: + None + """ + if (len(Mt5.positions_get(symbol=self.symbol)) == 0) and self.trading_time(): + if buy and not sell: + self.open_buy_position(comment) + self.total_deals += 1 + if sell and not buy: + self.open_sell_position(comment) + self.total_deals += 1 + + self.stop_and_gain(comment) + + if self.days_end(): + print("It is the end of trading the day.") + print("Closing all positions.") + self.close_position(comment) + self.summary() + + def close_position(self, comment: str = "") -> None: + """ + Close an open position. + + Args: + comment (str): A comment for the trade. + + Returns: + None + """ + # buy (0) and sell(1) + if len(Mt5.positions_get(symbol=self.symbol)) == 1: + if Mt5.positions_get(symbol=self.symbol)[0].type == 0: # if Buy + self.open_sell_position(comment) + + elif Mt5.positions_get(symbol=self.symbol)[0].type == 1: # if Sell + self.open_buy_position(comment) + + def stop_and_gain(self, comment: str = "") -> None: + """ + Check for stop loss and take profit conditions and close positions accordingly. + + Args: + comment (str): A comment for the trade. + + Returns: + None + """ + if len(Mt5.positions_get()) == 1: + points = ( + Mt5.positions_get()[0].profit + * Mt5.symbol_info(self.symbol).trade_tick_size + / Mt5.symbol_info(self.symbol).trade_tick_value + ) / Mt5.positions_get()[0].volume + + if points / Mt5.symbol_info(self.symbol).point >= self.take_profit: + self.profit_deals += 1 + self.close_position(comment) + print( + f"Take profit reached. (" + f"{Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[-1].profit}" + f")\n" + ) + if ( + Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[-1].symbol + == self.symbol + ): + self.balance += Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[ + -1 + ].profit + self.statistics() + + elif ((points / Mt5.symbol_info(self.symbol).point) * -1) >= self.stop_loss: + self.loss_deals += 1 + self.close_position(comment) + print( + f"Stop loss reached. (" + f"{Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[-1].profit}" + f")\n" + ) + if ( + Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[-1].symbol + == self.symbol + ): + self.balance += Mt5.history_deals_get((datetime.today() - timedelta(days=1)), datetime.now())[ + -1 + ].profit + self.statistics() + + def days_end(self) -> bool: + """ + Check if it is the end of trading for the day. + + Returns: + bool: True if it is the end of trading for the day, False otherwise. + """ + if datetime.now().hour >= int(self.ending_time_hour) and datetime.now().minute >= int(self.ending_time_minutes): + return True + return False + + def trading_time(self) -> bool: + """ + Check if it is within the allowed trading time. + + Returns: + bool: True if it is within the allowed trading time, False otherwise. + """ + if int(self.start_time_hour) < datetime.now().hour < int(self.finishing_time_hour): + return True + elif datetime.now().hour == int(self.start_time_hour): + if datetime.now().minute >= int(self.start_time_minutes): + return True + elif datetime.now().hour == int(self.finishing_time_hour): + if datetime.now().minute < int(self.finishing_time_minutes): + return True + return False diff --git a/mqpy/src/utilities.py b/mqpy/src/utilities.py new file mode 100644 index 0000000..073308e --- /dev/null +++ b/mqpy/src/utilities.py @@ -0,0 +1,57 @@ +from datetime import datetime + +import MetaTrader5 as Mt5 + + +class Utilities: + """A utility class for handling trading-related functionalities.""" + + def __init__(self) -> None: + """Initialize the Utilities class.""" + # Variables for minutes_counter + self.__minutes_counter: int = 0 + self.__counter_flag: bool = True + self.__allowed_to_trade: bool = True + self.__allow_to_count: bool = False + self.__recent_trade: bool = False + + def check_trade_availability(self, symbol: str, count_until: int) -> bool: + """ + Check if trading is allowed based on specified conditions. + + Args: + symbol (str): The financial instrument symbol. + count_until (int): The number of minutes until trading is allowed. + + Returns: + bool: True if trading is allowed, False otherwise. + """ + if len(Mt5.positions_get(symbol=symbol)) == 1: + self.__recent_trade = True + + if len(Mt5.positions_get(symbol=symbol)) != 1 and self.__recent_trade: + if not self.__allow_to_count: + self.__allow_to_count = True + self.__allowed_to_trade = False + self.__recent_trade = False + + if datetime.now().second == 0 and self.__counter_flag and self.__allow_to_count: + print(f"Trading will be allowed in {count_until - self.__minutes_counter} minutes.") + self.__minutes_counter += 1 + self.__counter_flag = False + + if datetime.now().second == 59: + self.__counter_flag = True + + if self.__minutes_counter == count_until: + print("Trading is allowed.\n") + self.__reset_counters() + + return self.__allowed_to_trade + + def __reset_counters(self) -> None: + """Reset counters after trading is allowed.""" + self.__minutes_counter = 0 + self.__counter_flag = True + self.__allow_to_count = False + self.__allowed_to_trade = True diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..607da0b --- /dev/null +++ b/poetry.lock @@ -0,0 +1,488 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "black" +version = "23.11.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"}, + {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"}, + {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"}, + {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"}, + {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"}, + {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"}, + {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"}, + {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"}, + {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"}, + {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"}, + {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"}, + {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"}, + {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"}, + {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"}, + {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"}, + {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"}, + {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"}, + {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "distlib" +version = "0.3.7" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, + {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "filelock" +version = "3.13.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] + +[[package]] +name = "identify" +version = "2.5.33" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, + {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "5.12.0" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, +] + +[package.extras] +colors = ["colorama (>=0.4.3)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "loguru" +version = "0.7.2" +description = "Python logging made (stupidly) simple" +optional = false +python-versions = ">=3.5" +files = [ + {file = "loguru-0.7.2-py3-none-any.whl", hash = "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb"}, + {file = "loguru-0.7.2.tar.gz", hash = "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac"}, +] + +[package.dependencies] +colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} +win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} + +[package.extras] +dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "mypy (==v1.5.1)", "pre-commit (==3.4.0)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"] + +[[package]] +name = "metatrader5" +version = "5.0.45" +description = "API Connector to MetaTrader 5 Terminal" +optional = false +python-versions = ">3.5, <4" +files = [ + {file = "MetaTrader5-5.0.45-cp310-cp310-win_amd64.whl", hash = "sha256:4306fdf45719640d18354011b99a5158c00459db2b265af8d952e0e4be238a98"}, + {file = "MetaTrader5-5.0.45-cp311-cp311-win_amd64.whl", hash = "sha256:ddcac27d97e055d656974ee8e2e323a7111aefeae775263afb8d1bfd5e104d79"}, + {file = "MetaTrader5-5.0.45-cp36-cp36m-win_amd64.whl", hash = "sha256:501b36baeec529cd4d1b7f2a9e4ac269954cb9359c0ee970221c445269d99114"}, + {file = "MetaTrader5-5.0.45-cp37-cp37m-win_amd64.whl", hash = "sha256:b1e90ffa12c982416163f8e96baa82e9a10c3055b7410da39acca702dbd0830e"}, + {file = "MetaTrader5-5.0.45-cp38-cp38-win_amd64.whl", hash = "sha256:5ce4fbd744e8734ac2c8073a980d06548c85b70ce409f74e0534a655f73c0422"}, + {file = "MetaTrader5-5.0.45-cp39-cp39-win_amd64.whl", hash = "sha256:a554a1584f531423238a8c6d04ae010bb28975cb30048ccad6a214f5cef150e1"}, +] + +[package.dependencies] +numpy = ">=1.7" + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nodeenv" +version = "1.8.0" +description = "Node.js virtual environment builder" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "numpy" +version = "1.24.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, + {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, + {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, + {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, + {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, + {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, + {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, + {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, + {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, + {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pathspec" +version = "0.11.2" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, +] + +[[package]] +name = "platformdirs" +version = "4.1.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, +] + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "3.5.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, + {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "pytest" +version = "7.4.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "setuptools" +version = "69.0.2" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, + {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typing-extensions" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, +] + +[[package]] +name = "virtualenv" +version = "20.25.0" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + +[[package]] +name = "win32-setctime" +version = "1.1.0" +description = "A small Python utility to set file creation time on Windows" +optional = false +python-versions = ">=3.5" +files = [ + {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, + {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, +] + +[package.extras] +dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "006438b10cb53f57d381b5e4ddedb12cb767dc76e115aa93bef15c430849b7c5" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ae9fd35 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,22 @@ +[tool.poetry] +name = "mqpy" +version = "v0.6.0" +description = "" +authors = ["Joao Paulo Euko"] +license = "MIT" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.8" +metatrader5 = "^5.0.45" +loguru = "^0.7.2" + +[tool.poetry.group.dev.dependencies] +pre-commit = "^3.5.0" +black = "^23.11.0" +isort = "^5.12.0" +pytest = "^7.4.3" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ff5f191 --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +import json +import os +import pathlib + +import setuptools + +long_description = (pathlib.Path(__file__).parent / "README.md").read_text() + +setuptools.setup( + name="mqpy", + version="v0.6.0", + description="", + author="Joao Paulo Euko", + license="MIT", + keywords=["metatrader5", "algotrading", "stock market"], + long_description_content_type="text/markdown", + packages=setuptools.find_packages(), + install_requires=[ + "metatrader5 == 5.0.45", + ], +)