Skip to content

fix: Tag not triggering package #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 28, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
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)
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