"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > MetaTraderOrder 관리 및 시장 데이터 수집을 통한 자동 거래

MetaTraderOrder 관리 및 시장 데이터 수집을 통한 자동 거래

2024-11-08에 게시됨
검색:168

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에서 복제됩니다. 침해가 있는 경우에는 Study_golang@163으로 문의하시기 바랍니다. .com에서 삭제하세요
최신 튜토리얼 더>
  • 어떤 각도에서든 이미지를 회전할 수 있는 React Hook 만들기
    어떤 각도에서든 이미지를 회전할 수 있는 React Hook 만들기
    웹 개발 시 이미지 회전이 필요할 수 있는데, 이는 CSS에서 쉽게 수행할 수 있습니다. 다음 변환과 같은 간단한 코드:rotate(90deg);. 하지만 JS에서 하고 싶다면 어떻게 해야 할까요? TLDR 브라우저 환경에서 캔버스에 이미지를 그려서 회전...
    프로그램 작성 2024-11-08에 게시됨
  • Lithe의 미들웨어: 작동 방식 및 자신만의 미들웨어를 만드는 방법
    Lithe의 미들웨어: 작동 방식 및 자신만의 미들웨어를 만드는 방법
    미들웨어는 애플리케이션에 들어오는 HTTP 요청을 검사하고 필터링하기 위한 편리한 메커니즘을 제공합니다. 예를 들어 Lithe에는 사용자가 인증되었는지 확인하는 미들웨어가 포함되어 있습니다. 그렇지 않은 경우 미들웨어는 사용자를 로그인 화면으로 리디렉션합니다. 사용자가...
    프로그램 작성 2024-11-08에 게시됨
  • JavaScript에서 반복되는 요소로 배열을 만드는 방법은 무엇입니까?
    JavaScript에서 반복되는 요소로 배열을 만드는 방법은 무엇입니까?
    JavaScript의 반복 요소 배열여러 번 반복되는 동일한 요소가 있는 배열을 만드는 것은 다양한 프로그래밍 시나리오에서 필수적입니다. Python에서는 [2] * 5와 같이 목록 곱셈을 통해 이를 달성할 수 있습니다. 그러나 이 기능은 JavaScript 배열에서 ...
    프로그램 작성 2024-11-08에 게시됨
  • ## MySQL의 LIKE와 LOCATE: 성능 측면에서 왕이 되는 연산자는 무엇입니까?
    ## MySQL의 LIKE와 LOCATE: 성능 측면에서 왕이 되는 연산자는 무엇입니까?
    MySQL LIKE 대 LOCATE 성능 비교MySQL에서 데이터를 검색할 때 LIKE와 LOCATE 중 어느 연산자가 더 효율적인지 궁금할 수 있습니다. 이 문서에서는 이 두 연산자 간의 성능 차이를 살펴봅니다.일반적인 사용 시나리오에서 LIKE는 LOCATE보다 약...
    프로그램 작성 2024-11-08에 게시됨
  • PHP를 사용하여 양식 데이터로 여러 MySQL 행을 업데이트하는 방법은 무엇입니까?
    PHP를 사용하여 양식 데이터로 여러 MySQL 행을 업데이트하는 방법은 무엇입니까?
    양식 데이터로 여러 MySQL 행 업데이트웹 개발에서는 사용자가 데이터베이스의 레코드를 편집할 수 있는 양식을 갖는 것이 일반적입니다. 일반적인 시나리오는 동일한 테이블의 여러 행을 수정된 데이터로 업데이트하는 것입니다. 이는 PHP와 MySQL을 사용하여 수행할 수 ...
    프로그램 작성 2024-11-08에 게시됨
  • Go에서 문자열에 []바이트를 할당할 수 없는 이유는 무엇입니까?
    Go에서 문자열에 []바이트를 할당할 수 없는 이유는 무엇입니까?
    바이트 할당 오류 이해: []바이트를 문자열에 할당할 수 없습니다.폴더 내의 파일을 읽으려고 시도하는 중에 오류가 발생했습니다. 파일의 내용을 읽으려고 할 때 "다중 할당에서 []바이트를 z(유형 문자열)에 할당할 수 없습니다." 이 오류의 원인을 자...
    프로그램 작성 2024-11-08에 게시됨
  • React 및 Typescript를 사용하여 사용자 정의 테이블 구성 요소를 만드는 방법(2부)
    React 및 Typescript를 사용하여 사용자 정의 테이블 구성 요소를 만드는 방법(2부)
    소개 예! ? 두 부분으로 구성된 이 시리즈의 마지막 부분에 도달했습니다! 아직 파트 1을 확인하지 않으셨다면 여기서 잠시 멈추고 먼저 파트 1을 살펴보세요. 걱정하지 마세요. 당신이 돌아올 때까지 기다리겠습니다! ? 1부에서는 CustomTable 구...
    프로그램 작성 2024-11-08에 게시됨
  • TypeScript 및 ioredis를 사용하여 Node.js에서 고성능 캐시 관리자 구축
    TypeScript 및 ioredis를 사용하여 Node.js에서 고성능 캐시 관리자 구축
    ioredis에 구축된 다용도의 사용하기 쉬운 캐시 관리자로 Node.js 앱 성능을 향상하세요. 캐싱을 단순화하고, 효율성을 최적화하고, 운영을 간소화하세요. 저는 사용 편의성과 성능에 중점을 두고 필요에 따라 ioredis를 기반으로 구축된 클래스를 개발했습니다. ...
    프로그램 작성 2024-11-08에 게시됨
  • 슈퍼클래스 참조 및 하위클래스 객체
    슈퍼클래스 참조 및 하위클래스 객체
    자바는 강력한 형식의 언어입니다. 기본 유형에는 표준 변환 및 자동 승격이 적용됩니다. 유형 호환성은 엄격하게 적용됩니다. 일반적으로 한 클래스의 참조 변수는 다른 클래스의 객체를 참조할 수 없습니다. 클래스 X와 Y가 구조적으로 동일하더라도 유형이 다르기 때문에 X...
    프로그램 작성 2024-11-08에 게시됨
  • Flexbox에서 flex-grow와 width는 어떻게 다릅니까?
    Flexbox에서 flex-grow와 width는 어떻게 다릅니까?
    Flexbox에서 flex-grow와 너비의 차이점Flexbox는 요소 간에 공간을 분배하는 두 가지 기본 방법인 flex-grow와 너비를 제공합니다. 효과적인 Flexbox 사용을 위해서는 이러한 속성 간의 차이점을 이해하는 것이 중요합니다.Flex-grow 대 너...
    프로그램 작성 2024-11-08에 게시됨
  • 양식 레이블과 입력을 같은 줄에 수평으로 정렬하는 방법은 무엇입니까?
    양식 레이블과 입력을 같은 줄에 수평으로 정렬하는 방법은 무엇입니까?
    양식 레이블의 수평 배치 및 동일한 행에 입력 달성웹 개발에서 양식의 미학은 사용자 경험에 매우 중요합니다. 레이블과 입력 필드를 같은 줄에 배열하면 양식의 가독성과 유용성을 향상시킬 수 있습니다. 이 문서에서는 길이에 관계없이 입력 요소를 해당 레이블과 원활하게 정렬...
    프로그램 작성 2024-11-08에 게시됨
  • 재귀 -1
    재귀 -1
    소개 1 함수가 자신을 호출하는 과정을 재귀라고 하며 해당 함수를 재귀 함수라고 합니다. 컴퓨터 프로그래밍은 수학의 기본적인 응용이므로 먼저 재귀 뒤에 숨어 있는 수학적 추론을 이해하려고 노력합니다. 일반적으로 우리 모두는 함수의 개념을 알고 있습니다...
    프로그램 작성 2024-11-08에 게시됨
  • Go API에 로깅 및 오류 처리 미들웨어 추가
    Go API에 로깅 및 오류 처리 미들웨어 추가
    빠른 참고: JWT 인증에 대한 이전 게시물을 확인하고 일부 렌더링 문제를 발견했다면 이제 해당 문제가 해결되었습니다! 이 예제는 해당 튜토리얼을 기반으로 구축되었으므로 다시 한 번 살펴보시기 바랍니다. :) 자 여러분, Go API를 실행하고 JWT 인증을 추가했으며...
    프로그램 작성 2024-11-08에 게시됨
  • Tensorflow 음악 예측
    Tensorflow 음악 예측
    이 글에서는 텐서플로우를 사용하여 음악 스타일을 예측하는 방법을 보여줍니다. 제 예에서는 테크노와 클래식 음악을 비교합니다. 내 Github에서 코드를 찾을 수 있습니다. https://github.com/victordalet/sound_to_partition ...
    프로그램 작성 2024-11-08에 게시됨
  • useEffect 후크 설명
    useEffect 후크 설명
    useEffect 후크는 React의 기본 부분으로, 기능적 구성 요소에서 부작용을 수행할 수 있도록 해줍니다. 자세한 내용은 다음과 같습니다. useEffect란 무엇인가요? useEffect 후크를 사용하면 구성 요소에서 데이터 가져오기, 구독 또는 ...
    프로그램 작성 2024-11-08에 게시됨

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3