Introduction
The aiomql package is an advanced algorithmic trading framework that enhances and extends the capabilities of the MetaTrader5 Python integration library (metatrader5). Its purpose is to simplify the process of building custom trading bots while offering a rich set of tools and abstractions tailored to algorithmic trading. The aiomql framework is designed with flexibility in mind, catering to a wide spectrum of users, from those looking for a lightweight asynchronous alternative to the MetaTrader5 Python integration to developers building complex, multi-strategy trading bots.
Requirements
This tutorial introduces version four of the aiomql framework, which boasts significant improvements in speed, efficiency, and design over its predecessors. A key highlight of this version is the inclusion of a powerful backtesting feature that allows users to test trading strategies on historical data before live deployment.
Although familiarity with previous versions of the aiomql framework may enhance your understanding, it is not a prerequisite. This tutorial is designed to be accessible even for beginners with no prior experience using the framework. However, to fully grasp and apply the concepts covered, a working knowledge of Python and a basic understanding of algorithmic trading are essential.
While this article serves primarily as an introduction to the framework rather than a step-by-step tutorial, it does include code snippets that require Python 3.11. If you experience compatibility issues with NumPy, you can resolve them by installing a supported version with the following command:
pip install numpy<v2
.
pip install aiomql
pip uninstall numpy
pip install 'numpy<v2'
Organization and Structure of aiomql
The aiomql framework is structured into three main sub-packages (core, contrib, and lib) along with a top-level module, _utils.py, that provides utility functions used throughout the framework. All classes, functions, constants, and other components can be accessed directly from the top level for convenience.
The MetaTrader Class
As previously mentioned, the aiomql library serves as an asynchronous counterpart to the metatrader5 package. This functionality is enabled through the MetaTrader class, a fundamental component of the framework. The class replicates the features of the metatrader5 library, providing its functions, constants, and specialized types as methods and attributes.
Key Features
The functions from the metatrader5 package are accessible as asynchronous instance methods within the MetaTrader class, retaining their original names. This design ensures seamless integration for users familiar with the original library while leveraging the benefits of asynchronous programming.
The MetaTrader class, designed as an asynchronous context manager, simplifies the management of the MetaTrader terminal. Upon entering the context, it automatically initializes the terminal and performs login operations. When exiting, it ensures the proper cleanup of resources and disconnection, even in the event of errors. This structure offers a clean and efficient approach to lifecycle management, making it particularly suitable for asynchronous workflows.
The non-asynchronous versions of these functions remain accessible but are prefixed with an underscore (_), signifying that they can be treated as private methods.
The MetaBackTester
The MetaBackTester is a subclass of MetaTrader designed specifically for backtesting. It utilizes a BackTestEngine instance, which can be provided during initialization or retrieved from the configuration. When the config.mode is set to "backtest", this class automatically replaces MetaTrader in applications that depend on it for terminal connectivity, ensuring seamless integration of backtesting functionality.
Base and _Base
The Base and _Base classes are foundational components that underpin other classes in the framework, providing essential utilities such as data validation, serialization, and seamless access to either a MetaTrader or MetaBackTester instance, depending on whether the system is in live trading or backtesting mode. While these classes are rarely used directly, they ensure consistency and reliability across the system by serving as the backbone for more specialized functionalities.
Base
The Base class offers robust data handling capabilities, focusing on validation and serialization. During instantiation, only attributes explicitly annotated in the class body or inherited from parent classes can be assigned values, and these values must strictly conform to their defined types, ensuring structured and type-safe data management.
Important Attributes and Methods
-
exclude (set):
A set of attribute names to exclude when accessing the attributes or generating a dictionary representation of the object. -
include (set):
A set of attribute names to include explicitly. This overrides the exclude set if both are provided. -
dict:
A property that returns all the attributes as a dictionary, applying the filters specified in the exclude and include sets. -
set_attributes(**kwargs):
A method to set attributes on the instance dynamically. It validates the inputs and ensures that they are of the correct type. -
get_dict(exclude: set = None, include: set = None):
A method to return the attributes of the instance as a dictionary, allowing the specification of exclude and include filters. The include parameter takes precedence over the exclude parameter if both are provided.
_Base
This class is a subclass of Base with additional attributes and functionality specifically designed for connecting to the terminal.
Important Attributes and Methods
-
config:
Represents the configuration instance. This attribute holds all the necessary configuration settings required for the class to function. -
mt5 (MetaTrader | MetaBackTester):
Provides an instance of either MetaTrader or MetaBackTester, determined by the mode attribute of the config object. The type of instance depends on whether the system is operating in live trading mode (MetaTrader) or backtesting mode (MetaBackTester).
Constants
The MetaTrader5 library organizes its extensive set of constants into specialized enums, improving clarity and functionality for developers. These enums represent various trading actions, order types, timeframes, and more, streamlining their use by grouping related constants under intuitive categories. Each enum provides attributes and, where applicable, additional methods or properties, enabling functionality like conversions, opposites, or derived values. This organization reduces errors, improves code readability, and makes constants easier to manage, particularly in complex trading applications.
Enums such as TradeAction, OrderFilling, and TimeFrame encapsulate the constants as integer values while offering Pythonic string representations for better usability. Some enums, like TimeFrame, include advanced methods to convert seconds into predefined time intervals or access all possible values. By structuring these constants systematically, the MetaTrader5 library ensures a more efficient and developer-friendly experience, simplifying interaction with trading operations and platform data.
Models
The models module provides an organized set of data-handling classes built on top of the MetaTrader5 library’s structures. All classes inherit from the Base class, which adds functionalities like data validation, serialization, and filtering to streamline their use. These classes represent various trading-related entities, such as OrderSendResult, SymbolInfo, and TradeRequest, allowing developers to efficiently interact with MetaTrader5's trading environment.
Each class encapsulates specific attributes and properties related to its corresponding trading entity, ensuring robust and structured data management. For instance, SymbolInfo provides details about financial instruments, while TradeRequest enables the creation and submission of trade operations. This modular design enhances readability, simplifies complex trading workflows, and ensures data consistency and ease of use for developers leveraging MetaTrader5 in their applications.
TaskQueue
The TaskQueue class efficiently manages background tasks for a bot or backtester using an instance asyncio.PriorityQueue for concurrent execution. It operates continuously in the background, allowing seamless integration with other components, such as the Trader class, which uses it to record trade data post-execution. Tasks are added to the queue via the add method, but they must first be encapsulated in a QueueItem, which holds task metadata such as arguments, priority, and completion requirements.
With configurable worker count, timeout settings, and task prioritization, the TaskQueue ensures robust task management and error handling. It supports finite or infinite execution modes and can gracefully clean up remaining tasks based on the priority before termination. This design enhances the workflow by offloading and managing background operations asynchronously, ensuring smooth and reliable functionality for complex trading or testing environments.
res = Result(result=result, parameters=params, name=name)
self.config.task_queue.add(item=QueueItem(res.save), must_complete=True)
Account
The Account class is a singleton designed to manage broker account details, ensuring that only one instance exists during the application’s lifecycle. It inherits from both Base and **_AccountInfo**, offering a structured and user-friendly interface for accessing account-specific information. This architecture ensures consistency and prevents duplicate instances, centralizing account management within the application.
As an AsyncContextManager, the Account class simplifies resource management by automating initialization and cleanup processes. When entering its context, it initializes the MetaTrader terminal and logs into the specified account. Upon exiting, it ensures proper resource shutdown and cleanup. This streamlined approach enhances the reliability of resource handling, making account management more intuitive and reducing the likelihood of errors during trading operations.
Important Methods and Attributes
-
connected (bool):
Indicates whether the login was successful and the connection to the terminal is active. Returns True if the account is connected. -
refresh():
Updates the account instance by retrieving the latest account details from the terminal, ensuring that the account data remains current.
Risk and Asset Management
The RAM class is responsible for managing risk assessment and management during trading activities. With attributes like risk_to_reward, fixed_amount, min_amount, max_amount, and risk, it allows traders to define and control their risk exposure effectively. These attributes provide flexibility in setting parameters for risk per trade, minimum and maximum risk amounts, and risk-to-reward ratios.
The class includes methods such as get_amount, which calculates the amount to risk per trade based on available margin and risk percentage, and check_losing_positions and check_open_positions, which ensure that the number of losing or open positions stays within predefined limits. By integrating these features, the RAM class provides a comprehensive approach to risk management, enhancing decision-making and promoting safer trading practices.
Important Attributes and Methods
-
risk (float):
The percentage of capital to risk per trade, expressed as a whole number (e.g., 1 for 1%). Defaults to 1. -
risk_to_reward (float):
The risk-to-reward ratio, indicating the relationship between potential risk and reward. Defaults to 2. -
fixed_amount (float):
A fixed amount to risk per trade, overriding percentage-based calculations if set. -
get_amount():
Calculates and returns the amount to risk per trade based on the configured attributes, such as risk, fixed_amount, min_amount, and max_amount.
The RAM class is best used in the a Trader class, where it can be used just before the trade is placed.
Candle and Candles
The Candle and Candles classes are custom tools for managing price bars retrieved from the terminal. The Candle class encapsulates data for a single price bar, ensuring mandatory attributes like Open, High, Low, and Close (OHLC) are present in every instance. It supports Python protocols, including hashing, iteration, and comparison, while providing methods like keys() and values() for attribute management. Additionally, it dynamically adds attributes passed during instantiation, allowing flexible customization.
The Candles class acts as a container for multiple Candle objects organized in chronological order. It utilizes a pandas DataFrame to store and manage its data, offering seamless integration with tools like pandas-ta for advanced technical analysis. By supporting various Python protocols, such as slicing and iteration, and extending functionality with specialized properties like timeframe, this class serves as a robust foundation for developing trading strategies. Its versatility ensures frequent utilization in complex analytical workflows.
Attributes and Methods of the Candle Class
-
time (int):
The start time of the candle's period. -
open (float):
The opening price of the candle. -
high (float):
The highest price reached during the candle's period. -
low (float):
The lowest price reached during the candle's period. -
close (float):
The closing price of the candle. -
tick_volume (float):
The tick volume during the candle's period. -
real_volume (float):
The actual traded volume during the candle's period. -
spread (float):
The spread during the candle's period. -
Index (int):
A custom attribute indicating the position of the candle in a sequence. -
set_attributes(**kwargs):
Dynamically sets attributes of the candle instance from the provided keyword arguments. -
is_bullish():
Returns True if the candle is bullish (closing price is greater than or equal to opening price), otherwise False. -
is_bearish():
Returns True if the candle is bearish (closing price is less than opening price), otherwise False. -
dict(exclude: set = None, include: set = None):
Returns a dictionary of the candle's attributes, optionally filtering attributes using exclude or include sets.
Attributes and Methods of the Candles Class
-
Index (Series[int]):
A pandas Series of the indexes of all candles in the object. -
time (Series[int]):
A pandas Series of the time of all candles in the object. -
open (Series[float]):
A pandas Series of the opening prices of all candles in the object. -
high (Series[float]):
A pandas Series of the highest prices of all candles in the object. -
low (Series[float]):
A pandas Series of the lowest prices of all candles in the object. -
close (Series[float]):
A pandas Series of the closing prices of all candles in the object. -
tick_volume (Series[float]):
A pandas Series of the tick volumes of all candles in the object. -
real_volume (Series[float]):
A pandas Series of the actual traded volumes of all candles in the object. -
spread (Series[float]):
A pandas Series of the spreads of all candles in the object. -
Candle (Type[Candle]):
The class used for representing individual candles within the object. -
timeframe (TimeFrame):
The timeframe of the candles, calculated from their timestamps. -
data (DataFrame):
The pandas DataFrame containing the underlying data of all candles in the object. -
rename(inplace=True, **kwargs):
Renames the columns of the underlying DataFrame. -
ta:
Provides access to the pandas-ta library for performing technical analysis directly on the candles, via the data attribute. -
ta_lib:
Provides access to the ta library for additional technical analysis, use this for functions that requires you to pass in the Series or the DataFrame object as an argument. -
columns:
Returns the column names of the underlying DataFrame.
Tick and Ticks
The Ticks and Tick classes are designed to manage tick data from the trading terminal, similar to the Candle classes. The Tick class represents an individual tick with attributes like bid, ask, last price, and volume, ensuring each instance encapsulates the necessary data for a single tick event. It supports dynamic attribute management and provides dictionary-like access, making it adaptable and easy to manipulate in different contexts.
The Ticks class acts as a container for multiple Tick objects, storing the data in a pandas DataFrame for efficient manipulation and analysis. It supports iteration, slicing, and various data operations, enabling seamless integration with tools like pandas-ta for technical analysis. This class is pivotal for handling large volumes of tick data in trading systems, providing a robust structure for real-time or historical data analysis.
Symbols
The _Symbol _ class provides a robust structure for encapsulating the data of financial instruments, supporting computations and operations required before initiating trades. As a subclass of _Base and SymbolInfo, it integrates extensive attributes and methods to handle financial instruments efficiently. This class can be tailored for various instruments from different brokers, ensuring adaptability across trading platforms.
With utility methods for accessing current tick data, managing market depth, and performing currency conversions, the Symbol class simplifies complex trading tasks. It offers functionality to initialize symbols, validate trading volumes, and retrieve historical rates or ticks, making it an essential component for developing trading strategies. Its design ensures that developers can extend and customize its behavior to suit specific trading requirements.
Important Attributes and Methods.
The Symbol class is a feature rich class. For the purpose of this introductory article I will only touch on some few vital ones, that you are most likely to use. tick and account are the only attributes of the Symbol class that are not the same as those defined in the SymbolInfo parent class.
-
tick (Tick):
Represents the current price tick of the financial instrument, providing real-time market data. -
account (Account):
An instance of the current trading account associated with the symbol. -
__init__(*, name: str, **kwargs):
Initializes a symbol instance. The name attribute is mandatory and must match the name of the symbol as specified by the broker in the terminal. -
initialize():
Populates the symbol instance with data from the terminal. It calls the info_tick method to retrieve the latest price tick and the info method to pull detailed symbol data. If successful, the select attribute is set to True, and all attributes are populated with server data. -
convert_currency(*, amount: float, from_currency: str, to_currency: str):
Converts a specified amount from one currency to another. -
amount_in_quote_currency(*, amount: float):
Converts an amount from the account currency to the quote currency if they are different. This method is especially useful for performing risk management calculations. -
info_tick:
Retrieves the current price tick of the financial instrument. -
symbol_select(enable: bool = True):
Adds or removes the symbol from the MarketWatch window. -
check_volume(volume: float):
Validates if a specified trading volume is within the allowed limits and adjusts it if necessary. -
round_off_volume(volume: float, round_down: bool = False):
Rounds the volume to the nearest valid step. -
compute_volume:
Computes the appropriate trading volume for a trade. -
copy_rates_from_pos(timeframe, start_position=0, count=500):
Fetches bars starting from a specific index. -
copy_rates_from(timeframe, date_from, count=500):
Retrieves historical rates (bars) starting from a specified date. -
copy_ticks_from(date_from, count=100, flags=CopyTicks.ALL):
Fetches tick data starting from a specified date.
The Symbol class is a versatile and feature-rich tool designed to manage financial instruments, providing essential methods for retrieving and converting data. While this introduction highlights key functionalities like initialization, currency conversion, and retrieving the latest tick data, many of its other features will be explored in future discussions. These include its integration into algorithmic trading systems, showcasing its adaptability for various use cases.
A notable contribution is the ForexSymbol class, a specialized extension of the Symbol class tailored for forex trading. This subclass is designed to handle the unique requirements of trading currency pairs, further demonstrating the flexibility and customization potential of the Symbol class for different trading scenarios.
Order
The Order class streamlines the management of trade orders by grouping related attributes and methods, making it easier to check, validate, and send orders. As a subclass of _Base and TradeRequest, it inherits robust functionality while offering additional convenience. With sensible defaults for attributes like action, type_time, and type_filling, it minimizes repetitive code during instantiation, ensuring efficiency and clarity in trading operations.
This class simplifies core tasks such as retrieving pending orders, checking fund sufficiency, and calculating margins, profits, and losses. The integration of methods like send() and check() ensures a seamless workflow for initiating and validating trade operations, while utilities like calc_margin() and calc_profit() assist in pre-trade analysis. Its design makes it an essential tool for implementing algorithmic trading strategies efficiently.
Important Attributes and Methods of the Order Class
-
__init__:
Initializes an order instance using keyword arguments that must be valid TradeRequest attributes. Defaults are set for action as DEAL, type_time as DAY, and type_filling as FOK, though they can be customized during instantiation. -
check(**kwargs):
Validates the order before placing it. Any keyword arguments provided will update the request object. -
send:
Sends the order to the terminal for execution. -
calc_margin:
Calculates the margin required for placing the trade. -
calc_profit:
Calculates the potential profit for the trade. -
calc_loss:
Calculates the potential loss for the trade. -
request:
This property returns the trade request object as a dictionary.
Trader
The Trader class serves as a utility-rich abstract base class for managing trade placements. It provides foundational methods for creating and managing various order types while handling critical processes like validation, sending, and recording of trades. This class requires implementation of the place_trade method in its subclasses, ensuring flexibility to suit specific trading strategies.
Key features include methods for setting stop-loss and take-profit levels based on pips or points, creating orders with or without stop levels, and calculating appropriate volumes for trades. The class integrates with a properly initialized Symbol instance and an optional RAM instance for risk assessment, enabling seamless trade management. It also supports trade result recording, facilitating tracking and analysis of executed trades.
Important Attributes and Methods of the Trader Class
-
modify_order(**kwargs):
Modifies the order attributes using the provided keyword arguments. -
modify_ram(**kwargs):
Updates the RAM (Risk Assessment and Management) instance attributes using the provided keyword arguments. -
check_order:
Validates the order before placing it, ensuring it meets the necessary criteria. -
send_order:
Sends the order to the broker for execution. -
record_trade(*, result: OrderSendResult, parameters: dict = None, name: str = ""):
Records trade details in a CSV or JSON file, delegating the task to the config.task_queue instance. Includes trade results and strategy parameters if provided.
The contrib package comes with two simple traders, ScalpTrader and SimpleTrader, one of which the ScalpTrader is shown below.
Session and Sessions
The Session and Sessions classes provide a robust framework for managing and enforcing trading times. A Session represents a defined time period in UTC with a start and end time, which can be specified as integers or datetime.time objects. These sessions can trigger predefined actions, such as closing all trades or only profitable/losing positions, or custom actions specified by the user. This allows strategies to maintain precise control over trading activities during specific periods.
The Sessions class groups multiple Session instances into a sorted collection, making it easy to manage overlapping or sequential trading periods. Acting as an asynchronous context manager, it continuously monitors the current time to determine the active session. If no session is active, the Sessions instance suspends trading operations until the next scheduled session begins, ensuring adherence to designated trading windows.
By integrating these classes, trading strategies can incorporate time-based rules with ease, enhancing their precision and reliability. This functionality is particularly useful in scenarios requiring strict adherence to trading hours, such as forex or stock market trading, or in automated systems where operations need to align with predefined time intervals.
Important Attributes and Methods of the Session Class
-
start (datetime.time):
The start time of the session in UTC. -
end (datetime.time):
The end time of the session in UTC. -
on_start (str):
Specifies the action to take when the session starts, such as "close_all", "close_win", "close_loss", or a custom action. -
on_end (str):
Specifies the action to take when the session ends, similar to on_start. -
custom_start (Callable):
An optional custom function to be executed when the session starts. -
custom_end (Callable):
An optional custom function to be executed when the session ends. -
name (str):
A name for the session, defaulting to a combination of the start and end times if not provided. -
in_session:
Checks if the current time is within the session. -
begin:
Executes the action specified by on_start or custom_start when the session begins. -
close:
Executes the action specified by on_end or custom_end when the session ends. -
duration:
Returns the duration of the session as a Duration object with hours, minutes, and seconds. -
close_all:
Closes all open positions when called. -
close_win:
Closes all winning positions when called. -
close_loss:
Closes all losing positions when called. -
action(action: str):
Executes the specified action, such as closing positions or triggering a custom function. -
until:
Calculates the time in seconds until the session starts from the current time.
Important Attributes and Methods of the Sessions Class
-
sessions (list[Session]):
A list of Session objects, sorted by their start times. -
current_session (Session | None):
The currently active session, if any. -
find(moment: datetime.time = None):
Finds and returns the session that includes the specified time. If no time is provided, the current time is used. -
find_next(moment: datetime.time = None):
Finds and returns the next session after the specified time. Defaults to the current time if no time is provided. -
check:
Monitors the current session. If no session is active, it waits until the next session begins. -
config:
The configuration instance associated with the sessions, determining the mode (live or backtesting).
Strategy
The Strategy class is the foundational framework for developing trading strategies that integrate seamlessly with both the Bot and the Backtester. As an abstract base class, it comes equipped with numerous features but requires the implementation of the trade method in derived classes. This method serves as the core trading logic for the strategy. The Strategy class acts as an asynchronous context manager and uses the run_strategy method to execute the strategy, invoking either the live_strategy or backtest_strategy method based on the operational mode.
With attributes like symbol, sessions, and parameters, the class ensures that strategies can be customized and tailored to specific financial instruments and trading sessions. The integration of cooperative multitasking methods, such as sleep and delay, ensures that the strategy remains efficient and synchronized with market updates, whether in live or backtesting environments. This makes the Strategy class a robust and flexible tool for building sophisticated trading systems.
Attributes and Methods
-
name (str):
The name of the strategy. Defaults to the class name if not explicitly provided. -
symbol (Symbol):
The financial instrument associated with the strategy. -
parameters (dict):
A dictionary of parameters specific to the strategy. -
sessions (Sessions):
The trading sessions during which the strategy is active. -
mt5 (MetaTrader | MetaBackTester):
The MetaTrader or MetaBackTester instance based on the mode (live or backtesting). -
config:
Configuration settings for the strategy. -
running (bool):
Indicates whether the strategy is currently running. -
backtest_controller (BackTestController):
A controller for managing backtesting operations. -
current_session (Session):
The currently active trading session. -
__init__(symbol: Symbol, params: dict = None, sessions: Sessions = None, name: str = ""):
Initializes the strategy with the given symbol, parameters, and sessions. -
run_strategy:
Runs the strategy by invoking either the live or backtesting method based on the mode. -
live_strategy:
Executes the strategy in live trading mode. -
backtest_strategy:
Executes the strategy in backtesting mode. -
trade:
Abstract method to be implemented by subclasses for placing trades. -
test:
Calls the trade method during backtesting if not implemented in the child class. -
live_sleep(secs: float):
Ensures synchronization with the terminal by computing precise sleep durations in live mode. -
backtest_sleep(secs: float):
Manages sleep durations during backtesting to align with the terminal's cursor. -
sleep(secs: float):
General sleep method that delegates to live_sleep or backtest_sleep based on the mode. -
delay(secs: float):
Introduces a delay for a specified number of seconds. Adjusts for live or backtest mode.
Position
The Position class is a utility class designed to manage and interact with open positions in a trading account. It allows filtering positions by attributes like ticket, symbol, or symbol group, providing flexible and efficient handling of active trades. Additionally, it includes methods for closing positions, either individually or in bulk, with support for executing opposite trades to close open positions.
Methods and Attributes
-
mt5 (MetaTrader | MetaBackTester):
The MetaTrader or MetaBackTester instance used for managing positions. -
positions (tuple[TradePosition, ...]):
A tuple of all currently open positions. -
total_positions (int):
The total number of open positions. -
get_positions(symbol: str = None, ticket: int = None, group: str = None):
Retrieves open positions, with optional filtering by symbol, ticket, or symbol group. -
get_position_by_ticket(ticket: int):
Retrieves a specific open position using its ticket number. -
get_positions_by_symbol(symbol: str):
Retrieves all open positions for a specific financial instrument. -
close(ticket: int, symbol: str, price: float, volume: float, order_type: OrderType):
Closes an open position using the provided ticket and parameters. -
close_position_by_ticket(ticket: int):
Closes a specific position identified by its ticket number. -
close_position(position: TradePosition):
Closes a position using a TradePosition object. - close_all(): Closes all open positions for the trading account.
- get_total_positions(): Returns the total number of currently open positions.
History
The History class is a utility for managing and retrieving completed trade deals and orders from an account’s trading history. It allows filtering and accessing historical data by parameters such as tickets, positions, or symbols, providing a detailed view of past trading activity. This class is particularly useful for analyzing trading performance or implementing post-trade analysis.
Methods and Attributes of the History Class
-
mt5 (MetaTrader | MetaBackTester):
The MetaTrader or MetaBackTester instance used for retrieving historical data. -
config (Config):
Configuration instance for managing operational settings. -
deals (tuple[TradeDeal, ...]):
A tuple containing the trade deals retrieved from the account's history. -
orders (tuple[TradeOrder, ...]):
A tuple containing the trade orders retrieved from the account's history. -
total_deals (int):
The total number of trade deals retrieved. -
total_orders (int):
The total number of trade orders retrieved. -
group (str):
A filter for selecting history by symbol group. - initialize(): Retrieves and populates trade deals and orders for the specified date range and group.
-
get_deals:
Fetches trade deals based on the parameters set during initialization. -
get_deals_by_ticket(ticket: int):
Filters and retrieves trade deals associated with a specific order ticket. -
get_deals_by_position(position: int):
Filters and retrieves trade deals associated with a specific position. -
get_orders:
Fetches trade orders based on the parameters set during initialization. -
get_orders_by_ticket(ticket: int):
Filters and retrieves trade orders associated with a specific order ticket. -
get_orders_by_position(position: int):
Filters and retrieves trade orders associated with a specific position.
Results
The Result class is a utility for recording trade outcomes and associated strategy parameters for tracking and analysis. It supports saving trade data in either CSV or JSON formats, based on the configured trade_record_mode. This functionality is critical for maintaining a detailed history of trades, enabling performance evaluation and strategy refinement.
Methods and Attributes of the Result Class
-
config (Config):
The configuration object managing settings like file directories and trade_record_mode. -
parameters (dict):
Additional parameters associated with the trade that need to be recorded. -
result (OrderSendResult):
The result of the executed trade, containing detailed trade information. -
name (str):
The name of the result file. Defaults to "Trades" if not explicitly provided. -
lock (Lock):
A threading lock to ensure thread-safe operations when saving results. -
get_data:
Combines trade result details and additional parameters into a single dictionary for saving. -
save(trade_record_mode: Literal['csv', 'json'] = None):
Saves the trade record in the specified format (CSV or JSON). Defaults to the mode configured in trade_record_mode. -
to_csv:
Saves the trade results and associated parameters to a CSV file. -
to_json:
Saves the trade results and associated parameters to a JSON file. -
serialize(value):
Converts the trade records and parameters to a string format for saving in JSON files.
The Result class ensures that trade outcomes are properly documented, enabling traders to analyze their strategies and improve future performance.
Trade Records
The TradeRecords class is a utility for managing and updating trade records stored in CSV or JSON files. It ensures that trade outcomes, including profits and win statuses, are updated accurately based on the actual trading history retrieved from the MetaTrader terminal. This functionality supports comprehensive trade tracking and analysis.
Methods and Attributes of the TradeRecords Class
-
config (Config):
Configuration instance for managing settings like record directories. -
mt5 (MetaTrader | MetaBackTester):
The MetaTrader or MetaBackTester instance used to retrieve trade data. -
records_dir (Path | str):
The directory where trade record files (CSV or JSON) are stored. -
positions (list[TradePosition] | None):
A list of currently open positions, retrieved dynamically. -
get_csv_records():
Retrieves all CSV trade record files from the records directory. -
get_json_records():
Retrieves all JSON trade record files from the records directory. -
read_update_csv(file: Path):
Reads and updates a specific CSV trade record file. -
read_update_json(file: Path):
Reads and updates a specific JSON trade record file. -
update_row(row: dict):
Updates a single row of trade data, calculating actual profit, win status, and closure status. -
update_rows(rows: list[dict]):
Updates multiple rows of trade data with actual outcomes. -
update_csv_records():
Updates all CSV trade records in the records directory. -
update_json_records():
Updates all JSON trade records in the records directory. -
update_csv_record(file: Path | str):
Updates a single specified CSV trade record file. -
update_json_record(file: Path | str):
Updates a single specified JSON trade record file. This class is essential for maintaining accurate and up-to-date trade records, facilitating robust performance analysis and strategy optimization.
Executor
The Executor class is a critical utility that powers both the Bot and BackTester, providing the capability to manage multiple strategies and tasks concurrently. It encapsulates a ThreadPoolExecutor to execute tasks efficiently in parallel, enabling seamless integration of strategies, coroutines, and functions within the trading framework.
Methods and Attributes of the Executor Class
-
executor (ThreadPoolExecutor):
The thread pool executor that manages concurrent task execution. -
strategy_runners (list[Strategy]):
A list of strategy instances to be executed. -
coroutines (list[Coroutine]):
A list of coroutine tasks to run. -
coroutine_threads (list[Coroutine]):
Coroutines that need to run on separate threads. -
functions (dict[Callable, dict]):
A dictionary of functions and their respective arguments to be executed. -
tasks (list[asyncio.Task]):
A list of asyncio tasks currently managed by the Executor. -
config (Config):
Configuration instance for managing executor settings. -
timeout:
Timeout setting for the Executor, used for testing purposes.
Key Methods
-
add_function(function: Callable, kwargs: dict = None):
Adds a function to the executor with optional arguments. -
add_coroutine(coroutine: Coroutine, kwargs: dict = None, on_separate_thread: bool = False):
Adds a coroutine to the executor, with an option to run it on a separate thread. -
add_strategies(strategies: tuple[Strategy]):
Adds multiple strategies to the executor. -
add_strategy(strategy: Strategy):
Adds a single strategy to the executor. -
run_strategy(strategy: Strategy):
Runs a single strategy using the asyncio event loop. -
run_coroutine_tasks():
Runs all coroutines managed by the executor. -
run_function(function: Callable, kwargs: dict):
Executes a single function with provided arguments. -
exit():
Gracefully shuts down the executor and cancels all running tasks. -
execute(workers: int = 5):
Executes all strategies, coroutines, and functions using the thread pool executor, with a configurable number of workers.
The Executor class ensures efficient execution of concurrent tasks, making it a robust solution for managing complex trading operations.
Bot
The Bot class is designed to run trading strategies in live mode, offering a structured and scalable framework for managing multiple strategies and symbols simultaneously. It connects with the *MetaTrader * terminal and uses the Executor class to efficiently handle concurrent tasks, such as executing strategies, managing coroutines, and running custom functions.
Methods and Attributes of the Bot Class Attributes
-
config (Config):
Configuration object for managing bot settings. -
executor (Executor):
Instance of the Executor class for concurrent task execution. -
mt (MetaTrader):
The MetaTrader instance for interacting with the trading terminal. -
strategies (list[Strategy]):
A list of trading strategies to be executed by the bot. -
__init__():
Initializes the bot with a configuration, executor, and MetaTrader instance. -
add_function(function: Callable, **kwargs):
Adds a custom function to the executor for execution. -
add_coroutine(coroutine: Coroutine, on_separate_thread: bool = False, **kwargs):
Adds a coroutine to the executor, optionally running it on a separate thread. -
add_strategy(strategy: Strategy):
Adds a single strategy to the bot's list of strategies. -
add_strategies(strategies: Iterable[Strategy]):
Adds multiple strategies to the bot at once. -
add_strategy_all(strategy: Type[Strategy], params: dict, symbols: list[Symbol], **kwargs):
Runs a single strategy on multiple symbols with the same parameters. -
initialize():
Asynchronously prepares the bot by signing in to the trading account, initializing symbols, and adding tasks to the executor. -
initialize_sync():
Synchronously prepares the bot, similar to initialize(). -
start():
Starts the bot by initializing it and invoking the executor. -
execute():
Executes the bot using the executor's thread pool. -
init_strategy(strategy: Strategy):
Initializes a single strategy asynchronously and adds it to the executor. -
init_strategies():
Asynchronously initializes all strategies added to the bot. -
init_strategy_sync(strategy: Strategy):
Synchronously initializes a single strategy and adds it to the executor. -
init_strategies_sync():
Synchronously initializes all strategies added to the bot.
The Bot class offers robust functionality for managing live trading strategies, ensuring efficient execution and streamlined integration with trading systems.
BackTester
The BackTester class provides a seamless way to backtest trading strategies, enabling developers to evaluate performance over historical data before deploying strategies live. Like the Bot class, the BackTester uses an Executor instance to manage multiple strategies concurrently. It integrates with a BackTestEngine to handle backtesting logic and operations. During backtesting, the mode attribute must be set to "backtest" to ensure proper functionality.
Methods and Attributes of the BackTester Class
-
config (Config):
Configuration object for managing backtester settings. -
executor (Executor):
Instance of the Executor class for managing concurrent strategy execution. -
mt (MetaBackTester):
MetaBackTester instance for interacting with the simulated trading environment. -
backtest_engine (BackTestEngine):
The engine responsible for managing backtesting operations. -
backtest_controller (BackTestController):
Manages synchronization and controls the backtesting process. -
strategies (list[Strategy]):
A list of trading strategies to be backtested. -
__init__(backtest_engine: BackTestEngine):
Initializes the BackTester with a BackTestEngine instance. -
initialize_sync():
Synchronously prepares the backtester, logging in and initializing strategies. -
initialize():
Asynchronously prepares the backtester, logging in and initializing strategies. -
execute():
Executes the backtester by initializing and running the executor. -
start():
Asynchronously initializes and starts the backtester. -
add_strategy(strategy: Strategy):
Adds a single strategy to the backtester. -
add_strategies(strategies: Iterable[Strategy]):
Adds multiple strategies to the backtester at once. -
add_strategy_all(strategy: Type[Strategy], params: dict, symbols: list[Symbol], **kwargs):
Runs a single strategy on multiple symbols using the same parameters. -
init_strategy(strategy: Strategy):
Asynchronously initializes a single strategy and adds it to the executor. -
init_strategy_sync(strategy: Strategy):
Synchronously initializes a single strategy and adds it to the executor. -
init_strategies():
Asynchronously initializes all strategies for the backtesting session. -
init_strategies_sync():
Synchronously initializes all strategies for the backtesting session.
The BackTester class, combined with its integration with the BackTestEngine and Executor, provides a robust framework for testing strategies, optimizing performance, and ensuring readiness for live trading environments.
Utils
The _utils module provides a collection of utility functions and decorators that encapsulate commonly needed logic for various parts of the framework. These utilities enhance code reusability, streamline repetitive tasks, and improve error handling and performance optimization.
Functions and Decorators in the _utils Module
-
backtest_sleep(secs: float):
Simulates an asynchronous sleep function for backtesting, synchronizing actions with the backtest engine's cursor. -
sleep(secs: float)
: Sleep until the interval specified. This is just like the sleep method in the Strategy class. -
dict_to_string(data: dict, multi: bool = False):
Converts a dictionary to a string format for logging, optionally formatting key-value pairs on separate lines. -
backoff_decorator(func=None, max_retries: int = 2, retries: int = 0, error=""):
Retries a function or coroutine a specified number of times before raising an error. Useful for handling transient issues. -
error_handler(func=None, msg: str = "", exe=Exception, response=None, log_error_msg: bool = True):
A decorator for catching and logging exceptions in asynchronous functions, with options to return a fallback response. -
error_handler_sync(func=None, msg: str = "", exe=Exception, response=None, log_error_msg: bool = True):
A synchronous version of the error_handler for standard functions. -
round_down(value: int | float, base: int):
Rounds a number down to the nearest multiple of the specified base. -
round_up(value: int | float, base: int):
Rounds a number up to the nearest multiple of the specified base. -
round_off(value: float, step: float, round_down: bool = False):
Rounds a number to the nearest step, with an option to specify rounding direction. -
async_cache(fun):
Caches the result of an asynchronous function to avoid redundant computations, improving performance.
These tools simplify implementation details and support developers in writing cleaner, more efficient, and maintainable code across the framework.
Conclusion
This is an introductory article that provides an overview of the powerful capabilities and features of this library, highlighting the key classes and functions essential for effectively leveraging it in trading systems. In the next tutorial, we’ll dive deeper into assembling these components to build a sophisticated and efficient trading system, guiding you step-by-step through the process.
If you found this article and the library helpful you can support my work by buying me a coffee. Your contributions go a long way in keeping this content flowing and inspiring more innovative ideas. Let’s learn and grow together!. Check out the repo here.
Top comments (0)