」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 使用 MetaTrader 訂單管理和市場資料收集進行自動交易

使用 MetaTrader 訂單管理和市場資料收集進行自動交易

發佈於2024-11-08
瀏覽:670

Automated Trading with MetaTraderOrder Management and Market Data Collection

Your AsimovMT class provides a comprehensive interface for interacting with MetaTrader5 (MT5) using Python. However, there are several areas in your code that could benefit from improvements, corrections, and enhancements to ensure robustness and maintainability. Below is a detailed review with suggestions:


1. Initialization and Error Handling

Issue:

In the __init__ method, if mt5.initialize() fails, you print an error message and call mt5.shutdown(), but the program continues to execute. This can lead to unexpected behavior since subsequent operations depend on a successful initialization.

Recommendation:

After shutting down MT5, you should raise an exception or exit the program to prevent further execution.

Code Correction:

def __init__(self):
    if not mt5.initialize():
        print("initialize() failed, error code =", mt5.last_error())
        mt5.shutdown()
        raise ConnectionError("Failed to initialize MetaTrader5.")

    # Rest of your initialization code...

2. Typographical Errors

Issue:

There is a consistent typo in the attribute name self.positons. It should be self.positions.

Impact:

This typo will lead to AttributeError when accessing or modifying self.positions elsewhere in the class.

Code Correction:

# Corrected attribute name
self.positions = [i._asdict() for i in mt5.positions_get()]

Ensure that all instances of self.positons are corrected to self.positions throughout the class, including methods like check_positions_and_orders.


3. Use of self in the Main Block

Issue:

In the __main__ block, you use self to refer to the instance of AsimovMT. Typically, self is reserved for instance methods within a class.

Recommendation:

Use a different variable name (e.g., asimov_mt) to avoid confusion.

Code Correction:

if __name__ == "__main__":
    # Instance
    asimov_mt = AsimovMT()

    # Testing methods using asimov_mt instead of self
    start_date = datetime.today() - timedelta(days=1)
    df_data = asimov_mt.get_ohlc_range('PETR4', 'M1', start_date, datetime.today())
    df_data = asimov_mt.get_ohlc_pos('PETR4', 'M1', 0, 1000)

    # ... and so on

4. Market Order Price Adjustment

Issue:

In the send_market_order method, you adjust the price by adding or subtracting 5 * ticks for buy and sell orders, respectively. Market orders are typically executed at the current market price without such adjustments.

Recommendation:

Use the current ask price for buy orders and bid price for sell orders without manual adjustments. If you intend to place a limit order, ensure that it aligns with your strategy.

Code Correction:

def send_market_order(self, symbol, side, volume, deviation=20, magic=1000, comment='test'):
    mt5.symbol_select(symbol, True)
    symbol_info = mt5.symbol_info(symbol)

    if side.lower() == 'buy':
        price = symbol_info.ask
        order_type = mt5.ORDER_TYPE_BUY
    elif side.lower() == 'sell':
        price = symbol_info.bid
        order_type = mt5.ORDER_TYPE_SELL
    else:
        raise ValueError("Invalid side. Use 'buy' or 'sell'.")

    if symbol_info.visible:
        request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": symbol,
            "volume": volume,
            "type": order_type,
            "price": price,
            "deviation": deviation,
            "magic": magic,
            "comment": comment,
            "type_time": mt5.ORDER_TIME_GTC,
            "type_filling": mt5.ORDER_FILLING_RETURN,
        }
        result = mt5.order_send(request)
        if result.retcode != mt5.TRADE_RETCODE_DONE:
            print(f"Order failed, retcode={result.retcode}")
        return result
    else:
        print(f"{symbol} not visible. Unable to send market order.")

5. Consistent Error Handling and Logging

Issue:

The current implementation uses print statements for error messages and notifications. This approach can be limiting for larger applications where logging levels and outputs need to be managed more granularly.

Recommendation:

Use Python’s built-in logging module to provide flexible and configurable logging.

Code Enhancement:

import logging

# Configure logging at the beginning of your script
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Replace print statements with logging
logging.info("MetaTrader5 loaded. Ready to start.")
logging.error(f"initialize() failed, error code = {mt5.last_error()}")

6. Validating Input Parameters

Issue:

Methods like send_limit_order and update_limit_order assume that input parameters are valid without performing checks.

Recommendation:

Add validation for input parameters to ensure they meet expected formats and constraints.

Code Example:

def send_limit_order(self, symbol, side, price, volume, magic=1000, comment=""):
    if side.lower() not in ['buy', 'sell']:
        raise ValueError("Invalid side. Use 'buy' or 'sell'.")
    if price 





7. Enhancing the tf_dict

Issue:

Your tf_dict maps timeframe strings to their MT5 constants and their equivalent in seconds. The comment suggests uncertainty about how timeframes represent days.

Recommendation:

Consider calculating the number of bars or days based on the timeframe and your specific use case. Additionally, you might want to include more descriptive information or helper methods to handle timeframe conversions.

Code Enhancement:

from enum import Enum

class TimeFrame(Enum):
    M1 = mt5.TIMEFRAME_M1
    M2 = mt5.TIMEFRAME_M2
    # ... other timeframes

self.tf_dict = {
    'M1': (TimeFrame.M1.value, 60),
    'M2': (TimeFrame.M2.value, 120),
    # ... other mappings
}

This approach makes the timeframes more manageable and less error-prone.


8. Handling copy_rates_range and copy_rates_from_pos Responses

Issue:

In methods get_ohlc_range and get_ohlc_pos, if data_raw is empty, the method returns None implicitly. This can lead to unexpected NoneType errors downstream.

Recommendation:

Explicitly handle empty responses by returning an empty DataFrame or raising an exception, depending on your use case.

Code Correction:

def get_ohlc_range(self, symbol, timeframe, start_date, end_date=datetime.now()):
    tf = self.tf_dict.get(timeframe, [None])[0]
    if tf is None:
        raise ValueError(f"Invalid timeframe: {timeframe}")

    data_raw = mt5.copy_rates_range(symbol, tf, start_date, end_date) 
    if data_raw is None:
        logging.warning("No data retrieved for the given range.")
        return pd.DataFrame()

    df_data = self._format_ohlc(data_raw)
    return df_data if df_data is not None else pd.DataFrame()

9. Improving the update_limit_order Method

Issue:

The update_limit_order method updates the order's price and volume but doesn't validate whether the order exists or whether the modification was successful.

Recommendation:

Check if the order exists before attempting to modify it and handle the response from order_send appropriately.

Code Enhancement:

def update_limit_order(self, order_id, price, volume):
    order = mt5.order_get(ticket=order_id)
    if order is None:
        logging.error(f"Order ID {order_id} not found.")
        return None

    request = {
        "action": mt5.TRADE_ACTION_MODIFY,
        "order": order_id,
        "price": price,
        "volume": volume,
    }
    result = mt5.order_send(request)
    if result.retcode != mt5.TRADE_RETCODE_DONE:
        logging.error(f"Failed to update order {order_id}, retcode={result.retcode}")
    return result._asdict()

10. Ensuring Thread Safety

Issue:

If you plan to use AsimovMT in a multi-threaded environment, concurrent access to shared resources like self.positions and self.orders could lead to race conditions.

Recommendation:

Implement thread synchronization mechanisms (e.g., threading locks) to protect shared resources.

Code Example:

import threading

class AsimovMT:
    def __init__(self):
        # Existing initialization code...
        self.lock = threading.Lock()

    def check_positions_and_orders(self):
        with self.lock:
            new_positions = [i._asdict() for i in mt5.positions_get()]
            new_orders = [i._asdict() for i in mt5.orders_get()]

            check = (self.positions != new_positions) or (self.orders != new_orders)
            self.positions = new_positions
            self.orders = new_orders
            return check

11. Finalizing MT5 Connection

Issue:

There’s no mechanism to properly shut down the MT5 connection when the program exits, which can lead to resource leaks.

Recommendation:

Implement a destructor method (__del__) or use context managers to ensure mt5.shutdown() is called appropriately.

Code Example Using Destructor:

def __del__(self):
    mt5.shutdown()
    logging.info("MetaTrader5 connection closed.")

Or Using Context Manager:

from contextlib import contextmanager

@contextmanager
def asimov_mt_context():
    asimov_mt = AsimovMT()
    try:
        yield asimov_mt
    finally:
        del asimov_mt

# Usage
if __name__ == "__main__":
    with asimov_mt_context() as asimov_mt:
        # Your testing code here

12. Enhancing Documentation and Readability

Issue:

The current code lacks docstrings and comments in English, which can hinder understanding and maintenance, especially for collaborators who may not speak Portuguese.

Recommendation:

Add docstrings to classes and methods, and ensure comments are in a consistent language (preferably English for broader accessibility).

Code Example:

class AsimovMT:
    """
    AsimovMT is a class that interfaces with MetaTrader5 to manage trading operations,
    retrieve market data, and monitor positions and orders.
    """

    def __init__(self):
        """
        Initializes the MetaTrader5 connection and retrieves current positions, orders,
        and historical data.
        """
        # Initialization code...

13. Sample Revised Main Block

Here’s how your __main__ block could look after applying the recommendations:

if __name__ == "__main__":
    try:
        asimov_mt = AsimovMT()

        # Testing market data methods
        start_date = datetime.today() - timedelta(days=1)
        df_range = asimov_mt.get_ohlc_range('PETR4', 'M1', start_date, datetime.today())
        print(df_range.head())

        df_pos = asimov_mt.get_ohlc_pos('PETR4', 'M1', 0, 1000)
        print(df_pos.head())

        # Testing balance methods
        positions_changed = asimov_mt.check_positions_and_orders()
        orders_changed = asimov_mt.check_positions_and_orders()
        print("Positions Changed:", positions_changed)
        print("Orders Changed:", orders_changed)

        h_positions_changed = asimov_mt.check_h_positions_and_orders(0)
        print("Historical Positions Changed:", h_positions_changed)
        print("Historical Deals:", asimov_mt.h_deals)
        print("Historical Orders:", asimov_mt.h_orders)

        # Testing order methods
        symbol = 'ITSA4'
        side = 'buy'
        volume = 100.0  # Should be float
        market_buy = asimov_mt.send_market_order(symbol, side, volume, comment='test')
        print("Market Buy Order:", market_buy)

        market_sell = asimov_mt.send_market_order(symbol, 'sell', volume, comment='test')
        print("Market Sell Order:", market_sell)

        limit_buy_price = 7.80
        limit_buy = asimov_mt.send_limit_order(symbol, 'buy', limit_buy_price, volume, comment='test')
        print("Limit Buy Order:", limit_buy)

        limit_sell_price = 8.00
        limit_sell = asimov_mt.send_limit_order(symbol, 'sell', limit_sell_price, volume, comment='test')
        print("Limit Sell Order:", limit_sell)

        # Update and cancel limit sell order
        if limit_sell:
            updated_order = asimov_mt.update_limit_order(limit_sell["order"], 8.01, volume=100.0)
            print("Updated Order:", updated_order)

            cancelled_order = asimov_mt.cancel_limit_order(limit_sell["order"])
            print("Cancelled Order:", cancelled_order)

    except Exception as e:
        logging.exception("An error occurred during execution.")

Conclusion

By addressing the issues and implementing the recommendations above, your AsimovMT class will become more robust, maintainable, and reliable. Proper error handling, input validation, and consistent naming conventions are crucial for developing scalable and professional-grade trading applications. Additionally, enhancing documentation and logging will aid in debugging and future development efforts.

Feel free to reach out if you have specific questions or need further assistance with particular aspects of your code!

版本聲明 本文轉載於:https://dev.to/vital7388/automated-trading-with-metatrader5-order-management-and-market-data-collection-4pb8?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • WordPress 遷移外掛程式終極指南
    WordPress 遷移外掛程式終極指南
    迁移 WordPress 网站就像收拾房子搬到新房子一样。确保所有内容(内容、主题、插件、媒体文件甚至数据库)完美移动且没有任何损坏的挑战似乎令人望而生畏。但就像搬家公司让搬家变得更容易一样,WordPress 迁移插件简化了将网站从一台主机移动到另一台主机的复杂过程。 无论您是切换主机、从本地开发...
    程式設計 發佈於2024-11-08
  • 如何使用穩健的解決方案來增強 PHP 中的 HTML 抓取
    如何使用穩健的解決方案來增強 PHP 中的 HTML 抓取
    PHP 中強大的HTML 抓取解決方案由於其挑剔和脆弱的性質,在PHP 中使用正則表達式進行HTML抓取可能具有挑戰性。若要獲得更強大、更可靠的方法,請考慮使用專門建置的 PHP 套件。 強烈推薦的選項之一是 PHP Simple HTML DOM Parser。該庫擅長處理 HTML(包括無效標籤...
    程式設計 發佈於2024-11-08
  • 如何偵測 Go 標準輸入 (Stdin) 中的資料可用性?
    如何偵測 Go 標準輸入 (Stdin) 中的資料可用性?
    使用Go 檢測標準輸入(Stdin) 中的資料可用性在Go 中,可以使用以下技術檢查標準輸入流(os.Stdin) 中的資料:驗證其檔案大小。它的工作原理如下:os.Stdin 可以像任何常規文件一樣對待,允許我們檢查其屬性。為此,我們使用 os.Stdin.Stat() 檢索 FileInfo 物...
    程式設計 發佈於2024-11-08
  • Wasp:Web 開發中 Django 的 JavaScript 答案
    Wasp:Web 開發中 Django 的 JavaScript 答案
    Wasp v Django: Building a full stack application just got a lot easier Hey, I’m Sam, a backend engineer with a lot of experience with Django....
    程式設計 發佈於2024-11-08
  • 如何在沒有鍵盤中斷的情況下透過按鍵中斷 While 迴圈?
    如何在沒有鍵盤中斷的情況下透過按鍵中斷 While 迴圈?
    透過按鍵中斷While 循環在使用while 循環讀取串行資料並將其寫入CSV 檔案的場景中,您可能希望為使用者提供終止循環以停止資料收集的選項。本文探討了在不明確使用鍵盤中斷的情況下實現此類功能的技術。 一個簡單的方法是利用 try- except 區塊來處理 KeyboardInterrupt ...
    程式設計 發佈於2024-11-08
  • 週 oot 訓練營學習
    週 oot 訓練營學習
    我決定邁出大膽的一步,參加由 LuxDevHQ 組織的我的第一個資料職業訓練營。這是一個為期 5 週的訓練營,旨在培養實踐資料技能。該訓練營旨在讓人們接觸至少 4 個專業領域的各種資料技能。 第一周以資訊會議開始,我進行了專案定向,並向我介紹了該專案並了解了整個專案的期望。 在這第一周,我學到了...
    程式設計 發佈於2024-11-08
  • 如何使用 Homebrew 和 jenv 在 Mac OS X 上管理多個 Java 版本?
    如何使用 Homebrew 和 jenv 在 Mac OS X 上管理多個 Java 版本?
    在Mac OS X 上管理多個Java 版本由於Java 管理其安裝的方式,在Mac OS X 上安裝多個Java 版本可能是一項挑戰。不過,有一個解決方案可以讓您輕鬆安裝和管理不同的 Java 版本:Homebrew。 使用 Homebrew 和 jenvHomebrew 是一個套件管理器,可以簡...
    程式設計 發佈於2024-11-08
  • 如何建立 React 應用程式?安裝與環境設置
    如何建立 React 應用程式?安裝與環境設置
    在開始使用 React 建立應用程式之前,擁有正確的開發環境非常重要。以下是幫助您入門的分步指南: 步驟 1. 安裝 Node.js 和 npm 設定 React 環境的第一步是安裝 Node.js,因為它提供了在瀏覽器外部執行程式碼所需的 JavaScript 執行程式時。當您安裝 Node.js...
    程式設計 發佈於2024-11-08
  • python 並發.futures
    python 並發.futures
    未来 Future 是一个容器,可以保存计算结果或计算期间发生的错误。创建 future 时,它​​以 PENDING 状态开始。该库不打算手动创建此对象,除非出于测试目的。 import concurrent.futures as futures f = futures.Futu...
    程式設計 發佈於2024-11-08
  • 使用純 Javascript 只需幾行即可實現飛向購物車的動畫。
    使用純 Javascript 只需幾行即可實現飛向購物車的動畫。
    最近,我偶然發現了一個舊教程,展示了使用 jQuery 實現飛行到購物車的動畫。我想透過使用純 JavaScript 實現相同的效果來挑戰自己。 我創建了一個包含產品和購物車圖示的簡單佈局。樣式並不重要,所以我們不會在這裡討論它。 訣竅是複製產品圖像,將其添加到產品元素之前。然後計算克隆圖像和購...
    程式設計 發佈於2024-11-08
  • Bokeh 是一個有趣的 Python 資料視覺化資料工具
    Bokeh 是一個有趣的 Python 資料視覺化資料工具
    資料視覺化在解釋大量資訊方面發揮關鍵作用。 Bokeh 等工具已成為建立互動式儀表板和報告的流行解決方案。每個工具都具有獨特的優勢,具體取決於您專案的複雜性和您首選的程式語言。在本文中,我們將深入研究每個工具,然後專注於 Bokeh,包括實踐範例和雲端中的部署。 以便... 什麼是散景? Bok...
    程式設計 發佈於2024-11-08
  • django-components v 模板現在與 Vue 或 React 相當
    django-components v 模板現在與 Vue 或 React 相當
    嘿,我是 Juro,我是 django-components 的維護者之一。在 v0.90-0.94 版本中,我們添加了一些功能,使模板中的元件使用更加靈活,類似於 JSX / Vue。 (此資訊已經有點過時了(一個月前發布;最新的是v0.101),因為我正忙著添加對JS / CSS 變數、Typ...
    程式設計 發佈於2024-11-08
  • 如何在 Go 中解密 AES ECB 模式加密?
    如何在 Go 中解密 AES ECB 模式加密?
    Go 中的AES ECB 加密Go 中的AES ECB 加密package main import ( "crypto/aes" "fmt" ) func decryptAes128Ecb(data, key []byte) []byte { ...
    程式設計 發佈於2024-11-08
  • 在 GitHub-echo 中實現 TOML 配置支持
    在 GitHub-echo 中實現 TOML 配置支持
    介绍 最近,我有机会通过添加对 TOML 配置文件的支持来增强 github-echo 命令行工具。此功能允许用户在 .github-echo-config.toml 文件中设置持久默认选项,从而减少每次使用该工具时手动输入重复配置的需要。在这篇文章中,我将向您介绍我在该功能上的经...
    程式設計 發佈於2024-11-08
  • 如何使用 SimpleXML 和 DOMDocument 刪除 XPath 節點?
    如何使用 SimpleXML 和 DOMDocument 刪除 XPath 節點?
    SimpleXML:刪除XPath 節點在本文中,我們將探討如何使用以下方法有效地從XML 文件中刪除父節點: SimpleXML 和XPath。 了解 SimpleXML限制提供的程式碼嘗試使用 SimpleXML 在透過 XPath 找到父節點後刪除它。然而,SimpleXML 的 unset(...
    程式設計 發佈於2024-11-08

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3