78c49238cf
* feat: add stable MT5Client public API and infrastructure layer Introduce a reusable public API for downstream trading applications: - MT5Client as the primary client abstraction with order_check/order_send - schemas module with DataKind contracts, validation, and normalization - converters, exceptions, retry, and storage facade modules - CLI order commands now route through MT5Client - connected_client made public; retry logic centralized - Contract tests for API surface, schemas, and storage round-trips - README and docs updated with Python API usage examples Co-authored-by: Daichi Narushima <dceoy@users.noreply.github.com> * fix: correct time coercion, broker-safe symbols, and execution docs - Normalize MT5 time columns with correct second/millisecond units - Coerce all present known MT5 time fields, including optional order times - Preserve broker symbol casing in normalize_symbol() - Document order_send() as a live execution primitive with clear scope boundaries - Add contract tests for timestamp and symbol normalization behavior Co-authored-by: Daichi Narushima <dceoy@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Daichi Narushima <dceoy@users.noreply.github.com>
91 lines
2.3 KiB
Python
91 lines
2.3 KiB
Python
"""Normalized exception types for MT5 and mt5cli operations."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, TypeVar
|
|
|
|
from pdmt5 import Mt5RuntimeError, Mt5TradingError
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
|
|
T = TypeVar("T")
|
|
|
|
__all__ = [
|
|
"Mt5CliError",
|
|
"Mt5ConnectionError",
|
|
"Mt5OperationError",
|
|
"Mt5SchemaError",
|
|
"call_with_normalized_errors",
|
|
"is_recoverable_mt5_error",
|
|
"normalize_mt5_exception",
|
|
]
|
|
|
|
_RECOVERABLE_MT5_ERRORS: tuple[type[BaseException], ...] = (
|
|
Mt5TradingError,
|
|
Mt5RuntimeError,
|
|
)
|
|
|
|
|
|
class Mt5CliError(Exception):
|
|
"""Base exception for mt5cli public API errors."""
|
|
|
|
|
|
class Mt5ConnectionError(Mt5CliError):
|
|
"""Raised when MT5 initialization, login, or shutdown fails."""
|
|
|
|
|
|
class Mt5OperationError(Mt5CliError):
|
|
"""Raised when an MT5 data or trading operation fails."""
|
|
|
|
|
|
class Mt5SchemaError(Mt5CliError):
|
|
"""Raised when a DataFrame does not match an expected dataset schema."""
|
|
|
|
|
|
def is_recoverable_mt5_error(exc: BaseException) -> bool:
|
|
"""Return whether an exception is a transient MT5 failure worth retrying.
|
|
|
|
Args:
|
|
exc: Exception raised by MT5 or pdmt5.
|
|
|
|
Returns:
|
|
True for ``Mt5RuntimeError`` and ``Mt5TradingError``.
|
|
"""
|
|
return isinstance(exc, _RECOVERABLE_MT5_ERRORS)
|
|
|
|
|
|
def normalize_mt5_exception(exc: BaseException) -> Mt5CliError:
|
|
"""Map pdmt5/MT5 exceptions to stable mt5cli exception types.
|
|
|
|
Args:
|
|
exc: Original exception from MT5 or pdmt5.
|
|
|
|
Returns:
|
|
``Mt5ConnectionError`` for runtime failures, ``Mt5OperationError`` for
|
|
trading failures, or the original exception when it is not recognized.
|
|
"""
|
|
if isinstance(exc, Mt5TradingError):
|
|
return Mt5OperationError(str(exc))
|
|
if isinstance(exc, Mt5RuntimeError):
|
|
return Mt5ConnectionError(str(exc))
|
|
if isinstance(exc, Mt5CliError):
|
|
return exc
|
|
return Mt5CliError(str(exc))
|
|
|
|
|
|
def call_with_normalized_errors(fn: Callable[[], T]) -> T:
|
|
"""Run ``fn`` and map recoverable MT5 errors to mt5cli types.
|
|
|
|
Args:
|
|
fn: Callable performing MT5 work.
|
|
|
|
Returns:
|
|
Value returned by ``fn``.
|
|
"""
|
|
try:
|
|
return fn()
|
|
except _RECOVERABLE_MT5_ERRORS as exc:
|
|
normalized = normalize_mt5_exception(exc)
|
|
raise normalized from exc
|