Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Joaopeuko/Mql5-Python-Integration
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.6.10
Choose a base ref
...
head repository: Joaopeuko/Mql5-Python-Integration
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
  • 3 commits
  • 9 files changed
  • 2 contributors

Commits on Apr 28, 2025

  1. fix: Tag not triggering package (#40)

    ### Description
    
    Add package manual trigger.
    Fix `tests` in live mode. (Trade works locally but not in CI due to
    headless mode. I don't want to spend too much time making it work).
    
    Fixes #39
    Joaopeuko authored Apr 28, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    b95bef0 View commit details
  2. chore(release): v0.6.11

    semantic-release committed Apr 28, 2025
    Copy the full SHA
    be9d046 View commit details

Commits on Apr 29, 2025

  1. 44 docs update main readmemd (#45)

    ### Description
    
    Update main README.md.
    
    Fixes #44
    Joaopeuko authored Apr 29, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    4d488d1 View commit details
Showing with 252 additions and 184 deletions.
  1. +4 −3 .github/workflows/deploy-pypi-packages.yaml
  2. +1 −0 .github/workflows/test-pytest-and-integration.yml
  3. +15 −0 CHANGELOG.md
  4. +32 −57 README.md
  5. +11 −38 mqpy/trade.py
  6. +1 −1 pyproject.toml
  7. +38 −1 tests/conftest.py
  8. +1 −1 tests/test_book.py
  9. +149 −83 tests/test_trade.py
7 changes: 4 additions & 3 deletions .github/workflows/deploy-pypi-packages.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Deploy | Publish Pypi Packages

on:
workflow_dispatch:
push:
branches:
- '**' # All branches for Test PyPI
@@ -92,7 +93,7 @@ jobs:
Move-Item -Path pyproject.toml.bak -Destination pyproject.toml -Force
- name: Build package for PyPI
if: startsWith(github.ref, 'refs/tags/')
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
run: |
python -m build
@@ -112,8 +113,8 @@ jobs:
# Upload with verbose output for debugging
twine upload --skip-existing --verbose --repository-url https://test.pypi.org/legacy/ dist/*
- name: Publish to PyPI (new tag)
if: startsWith(github.ref, 'refs/tags/')
- name: Publish to PyPI (new tag or workflow dispatch)
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
1 change: 1 addition & 0 deletions .github/workflows/test-pytest-and-integration.yml
Original file line number Diff line number Diff line change
@@ -77,6 +77,7 @@ jobs:
- name: Run tests with coverage
env:
HEADLESS_MODE: true
MT5_LOGIN: ${{ secrets.MT5_LOGIN }}
MT5_PASSWORD: ${{ secrets.MT5_PASSWORD }}
MT5_SERVER: "MetaQuotes-Demo"
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# CHANGELOG


## v0.6.11 (2025-04-28)

### Bug Fixes

- Tag not triggering package ([#40](https://github.com/Joaopeuko/Mql5-Python-Integration/pull/40),
[`b95bef0`](https://github.com/Joaopeuko/Mql5-Python-Integration/commit/b95bef0c800dda14a6c89933c6f4b1385a80ea1f))

### Description

Add package manual trigger. Fix `tests` in live mode. (Trade works locally but not in CI due to
headless mode. I don't want to spend too much time making it work).

Fixes #39


## v0.6.10 (2025-04-27)

### Bug Fixes
89 changes: 32 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Mql5-Python-Integration (MQPy)

<p align="center">
<img src="docs/assets/logo.svg" alt="MQPy Logo" width="200" height="200">
</p>
@@ -9,84 +11,57 @@
<img src="https://img.shields.io/pypi/l/mqpy" alt="PyPI - License">
</p>

<h1 align="center">Mql5-Python-Integration (MQPy)</h1>

<p align="center"><strong>Current Version: v0.6.9</strong></p>

Welcome to the Mql5-Python-Integration project! This project facilitates the integration between MetaTrader 5 (Mql5) and Python, allowing for efficient algorithmic trading strategies.

## ⚠️ TRADING RISK WARNING
A Python library designed to simplify the process of creating Expert Advisors for MetaTrader 5. While developing directly in MQL5 can be complex, MQPy provides a more streamlined experience using Python.

**IMPORTANT: Trading involves substantial risk of loss and is not suitable for all investors.**
## ⚠️ Important Notice

- Always use a **demo account** with fake money when testing strategies
- MQPy is provided for **educational purposes only**
- Past performance is not indicative of future results
Trading involves risk. Always:
- Use demo accounts for testing
- Never trade with money you cannot afford to lose
- The developers are not responsible for any financial losses incurred from using this software

## Table of Contents

- [⚠️ TRADING RISK WARNING](#️-trading-risk-warning)
- [Table of Contents](#table-of-contents)
- [Project Update: Changes in Progress](#project-update-changes-in-progress)
- [Installation](#installation)
- [Usage](#usage)
- [Generate the File](#generate-the-file)
- [Missing Features/Good Practice](#missing-featuresgood-practice)
- [Delicate Metatrader5 Environment](#delicate-metatrader5-environment)
- [Alternative Libraries](#alternative-libraries)

## Project Update: Changes in Progress

🚧 **Work in Progress: v0.6.9**
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.

📌 **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).
- Understand that past performance doesn't guarantee future results

## Installation

**Note: In order to use this package, you need to have MetaTrader 5 installed on a Windows system with Python 3.8 or later.**

To install the package, you can use the following command:

```bash
pip install mqpy
```

Make sure to fulfill the prerequisites mentioned above before attempting to use the Mql5-Python-Integration (MQPy) package.

## Usage
## Requirements

Basic Usage
- Windows OS
- Python 3.8 or later
- MetaTrader 5 installed

Once installed, you can use the mqpy command to generate the boilerplate code.
## Quick Start

### Generate the File

To create a template file for a trading strategy, use the following command:
Generate a trading strategy template:

```bash
mqpy --symbol <Symbol> --file_name <File Name>
mqpy --symbol EURUSD --file_name my_strategy
```

Please change `<Symbol>` and `<File Name>` to the desired values. For example:

```bash
mqpy --symbol EURUSD --file_name demo
```
## Features

## Missing Features/Good Practice
- Simple integration with MetaTrader 5
- Easy-to-use command line interface
- Basic template generation for trading strategies
- Support for various trading strategies:
- Moving Average Crossover
- RSI-based trading
- Bollinger Bands strategies
- Fibonacci Retracement patterns
- Multi-timeframe analysis
- Custom indicator integration

This library has been in existence for several years and was designed to be simple and straightforward. While there are plans to enhance it with features such as logging and other components to improve its overall quality, there are considerations specific to the nature of the Metatrader5 library.
## Documentation

### Delicate Metatrader5 Environment
For detailed documentation, examples, and strategy explanations, visit:
[https://joaopeuko.com/Mql5-Python-Integration/](https://joaopeuko.com/Mql5-Python-Integration/)

Metatrader5 operates within a highly restrictive environment, and certain practices that may be considered best practices in other contexts might cause trouble for newcomers in software development, which is the main focus of this library. For the sake of simplicity and ease of use, the library currently retains some practices that may not align with conventional best practices.
## Support

### Alternative Libraries
MQPy is a free and open-source project. If you'd like to support its development, consider becoming a sponsor.

For users seeking a more advanced library with a similar concept, consider exploring the following alternative:
## License

[metatrader5EasyT](https://github.com/Joaopeuko/metatrader5EasyT): A more advanced library that aligns with best practices while providing a similar user-friendly approach. It is also available on PyPI.
This project is licensed under the MIT License - see the LICENSE file for details.
49 changes: 11 additions & 38 deletions mqpy/trade.py
Original file line number Diff line number Diff line change
@@ -224,18 +224,6 @@ def open_buy_position(self, comment: str = "") -> None:
Returns:
None
"""
# Check trade mode to see if Buy operations are allowed
symbol_info = Mt5.symbol_info(self.symbol)
if symbol_info.trade_mode == 0:
logger.warning(f"Cannot open Buy position for {self.symbol} - trading is disabled.")
return
if symbol_info.trade_mode == 2: # Short only
logger.warning(f"Cannot open Buy position for {self.symbol} - only Sell positions are allowed.")
return
if symbol_info.trade_mode == 4 and len(Mt5.positions_get(symbol=self.symbol)) == 0:
logger.warning(f"Cannot open Buy position for {self.symbol} - symbol is in 'Close only' mode.")
return

point = Mt5.symbol_info(self.symbol).point
price = Mt5.symbol_info_tick(self.symbol).ask

@@ -268,18 +256,6 @@ def open_sell_position(self, comment: str = "") -> None:
Returns:
None
"""
# Check trade mode to see if Sell operations are allowed
symbol_info = Mt5.symbol_info(self.symbol)
if symbol_info.trade_mode == 0:
logger.warning(f"Cannot open Sell position for {self.symbol} - trading is disabled.")
return
if symbol_info.trade_mode == 1: # Long only
logger.warning(f"Cannot open Sell position for {self.symbol} - only Buy positions are allowed.")
return
if symbol_info.trade_mode == 4 and len(Mt5.positions_get(symbol=self.symbol)) == 0:
logger.warning(f"Cannot open Sell position for {self.symbol} - symbol is in 'Close only' mode.")
return

point = Mt5.symbol_info(self.symbol).point
price = Mt5.symbol_info_tick(self.symbol).bid

@@ -383,27 +359,24 @@ def _handle_position_by_trade_mode(
self.total_deals += 1

def open_position(self, *, should_buy: bool, should_sell: bool, comment: str = "") -> None:
"""Open a position based on buy and sell conditions.
"""Open a position based on the given conditions.
Args:
should_buy (bool): True if a Buy position should be opened, False otherwise.
should_sell (bool): True if a Sell position should be opened, False otherwise.
comment (str): A comment for the trade.
should_buy: Whether to open a buy position.
should_sell: Whether to open a sell position.
comment: Optional comment for the position.
Returns:
None
"""
symbol_info = Mt5.symbol_info(self.symbol)

# Check trade mode restrictions
if self._handle_trade_mode_restrictions(symbol_info):
return

# Open a position if no existing positions and within trading time
if (len(Mt5.positions_get(symbol=self.symbol)) == 0) and self.trading_time():
self._handle_position_by_trade_mode(
symbol_info, should_buy=should_buy, should_sell=should_sell, comment=comment
)
if self.trading_time():
if should_buy and not should_sell:
self.open_buy_position(comment)
self.total_deals += 1
if should_sell and not should_buy:
self.open_sell_position(comment)
self.total_deals += 1

# Check for stop loss and take profit conditions
self.stop_and_gain(comment)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ name = "mqpy"
authors = [
{email = "joao@example.com", name = "Joao Euko"},
]
version = "0.6.10"
version = "0.6.11"
description = "I developed this library to simplify the process of creating an Expert Advisor in MQL5. While developing in MQL5 can be complex, the same task is more streamlined in Python."
requires-python = ">=3.8"
dependencies = []
39 changes: 38 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -2,11 +2,35 @@

from __future__ import annotations

import ctypes
import logging
from typing import Generator
import time
from typing import TYPE_CHECKING, Generator

import pytest

if TYPE_CHECKING:
from mqpy.trade import Trade

VK_CONTROL = 0x11
VK_E = 0x45

logger = logging.getLogger(__name__)


def send_ctrl_e() -> None:
"""Send CTRL+E to MetaTrader 5 to enable Expert Advisors."""
user32 = ctypes.windll.user32
# Press CTRL
user32.keybd_event(VK_CONTROL, 0, 0, 0)
# Press E
user32.keybd_event(VK_E, 0, 0, 0)
# Release E
user32.keybd_event(VK_E, 0, 2, 0)
# Release CTRL
user32.keybd_event(VK_CONTROL, 0, 2, 0)
time.sleep(1)


@pytest.fixture
def test_symbols() -> dict[str, str]:
@@ -32,3 +56,16 @@ def configure_logging() -> Generator[None, None, None]:

for handler in root.handlers[:]:
root.removeHandler(handler)


@pytest.fixture
def enable_autotrade(trade: Trade) -> Trade:
"""Enables autotrade for testing purposes."""
send_ctrl_e()

trade.start_time_hour = "0"
trade.start_time_minutes = "00"
trade.finishing_time_hour = "23"
trade.finishing_time_minutes = "59"

return trade
2 changes: 1 addition & 1 deletion tests/test_book.py
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@ def test_book_get(symbol: str) -> None:
assert market_data is not None

if market_data:
assert isinstance(market_data, list)
assert isinstance(market_data, (list, tuple))

# Loop separately to check for bids and asks
has_bids = False
Loading