Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

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
Show file tree
Hide file tree
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 7 .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
Expand Down Expand Up @@ -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

Expand All @@ -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 }}
Expand Down
1 change: 1 addition & 0 deletions 1 .github/workflows/test-pytest-and-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
49 changes: 11 additions & 38 deletions 49 mqpy/trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
39 changes: 38 additions & 1 deletion 39 tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand All @@ -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 2 tests/test_book.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.