English Русский Español Deutsch 日本語 Português
preview
将 MQL5 与数据处理包集成(第 3 部分):增强的数据可视化

将 MQL5 与数据处理包集成(第 3 部分):增强的数据可视化

MetaTrader 5示例 |
345 4
Hlomohang John Borotho
Hlomohang John Borotho

概述

金融市场的交易者经常面临理解大量数据的挑战,从价格波动和交易量到技术指标和经济新闻。随着现代市场的速度和复杂性,使用传统方法有效地解释这些数据流变得越来越困难。仅凭图表可能无法提供足够的洞察力,导致错失机会或做出不合时宜的决定。快速识别趋势、逆转和潜在风险的需要增加了难度。对于希望做出明智、数据驱动决策的交易者来说,无法从数据中提取关键见解是一个关键问题,可能会导致利润损失或风险增加。

增强的数据可视化通过将原始金融数据转换为更直观和交互式的视觉表示来解决这一挑战。动态蜡烛图、技术指标叠加图和回报热图等工具为交易者提供了对市场状况更深入、更可行的理解。通过整合突出趋势、相关性和异常的视觉元素,交易者可以快速发现机会并做出更明智的决策。这种增强的方法有助于降低解释数据的复杂性,使交易者能够在快速发展的金融市场中更加自信和高效地行事。


收集历史数据

from datetime import datetime
import MetaTrader5 as mt5
import pandas as pd
import pytz

# Display data on the MetaTrader 5 package
print("MetaTrader5 package author: ", mt5.__author__)
print("MetaTrader5 package version: ", mt5.__version__)

# Configure pandas display options
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1500)

# Establish connection to MetaTrader 5 terminal
if not mt5.initialize():
    print("initialize() failed, error code =", mt5.last_error())
    quit()

# Set time zone to UTC
timezone = pytz.timezone("Etc/UTC")
# Create 'datetime' objects in UTC time zone to avoid the implementation of a local time zone offset
utc_from = datetime(2024, 1, 2, tzinfo=timezone)
utc_to = datetime.now(timezone)  # Set to the current date and time

# Get bars from XAUUSD H1 (hourly timeframe) within the specified interval
rates = mt5.copy_rates_range("XAUUSD", mt5.TIMEFRAME_H1, utc_from, utc_to)

# Shut down connection to the MetaTrader 5 terminal
mt5.shutdown()

# Check if data was retrieved
if rates is None or len(rates) == 0:
    print("No data retrieved. Please check the symbol or date range.")
else:
    # Display each element of obtained data in a new line (for the first 10 entries)
    print("Display obtained data 'as is'")
    for rate in rates[:10]:
        print(rate)

    # Create DataFrame out of the obtained data
    rates_frame = pd.DataFrame(rates)
    # Convert time in seconds into the 'datetime' format
    rates_frame['time'] = pd.to_datetime(rates_frame['time'], unit='s')

    # Save the data to a CSV file
    filename = "XAUUSD_H1_2nd.csv"
    rates_frame.to_csv(filename, index=False)
    print(f"\nData saved to file: {filename}")

为了检索历史数据,我们首先使用 “mt5.initialize()” 函数建立与 MetaTrader 5 终端的连接。这是必不可少的,因为 Python 包直接与正在运行的 MetaTrader 5 平台通信。我们通过指定开始和结束日期来配置代码,以设置数据提取所需的时间范围。`datetime` 对象是在 UTC 时区创建的,以确保跨不同时区的一致性。然后,脚本使用 `mt5.copy-rates-range()` 函数请求 XAUUSD 交易品种的历史小时数据,从 2024 年 1 月 2 日开始到当前日期和时间。

获取历史数据后,我们使用 “mt5.shutdown()” 安全地断开与 MetaTrader 5 终端的连接,以避免任何进一步的不必要的连接。获取到的数据最初以原始格式显示,以确认数据提取成功。我们将这些数据转换为 pandas DataFrame 以便于操作和分析。此外,该代码将 Unix 时间戳转换为可读的日期时间格式,确保数据结构良好,可供进一步处理或分析。这种方法允许交易者分析历史市场走势,并根据过去的表现做出明智的交易决策。

filename = "XAUUSD_H1_2nd.csv"
rates_frame.to_csv(filename, index=False)
print(f"\nData saved to file: {filename}")

由于我的操作系统是 Linux,我必须将收到的数据保存到一个文件中。但对于那些使用 Windows 的人来说,您只需使用以下脚本即可检索数据:

from datetime import datetime
import MetaTrader5 as mt5
import pandas as pd
import pytz

# Display data on the MetaTrader 5 package
print("MetaTrader5 package author: ", mt5.__author__)
print("MetaTrader5 package version: ", mt5.__version__)

# Configure pandas display options
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1500)

# Establish connection to MetaTrader 5 terminal
if not mt5.initialize():
    print("initialize() failed, error code =", mt5.last_error())
    quit()

# Set time zone to UTC
timezone = pytz.timezone("Etc/UTC")
# Create 'datetime' objects in UTC time zone to avoid the implementation of a local time zone offset
utc_from = datetime(2024, 1, 2, tzinfo=timezone)
utc_to = datetime.now(timezone)  # Set to the current date and time

# Get bars from XAUUSD H1 (hourly timeframe) within the specified interval
rates = mt5.copy_rates_range("XAUUSD", mt5.TIMEFRAME_H1, utc_from, utc_to)

# Shut down connection to the MetaTrader 5 terminal
mt5.shutdown()

# Check if data was retrieved
if rates is None or len(rates) == 0:
    print("No data retrieved. Please check the symbol or date range.")
else:
    # Display each element of obtained data in a new line (for the first 10 entries)
    print("Display obtained data 'as is'")
    for rate in rates[:10]:
        print(rate)

    # Create DataFrame out of the obtained data
    rates_frame = pd.DataFrame(rates)
    # Convert time in seconds into the 'datetime' format
    rates_frame['time'] = pd.to_datetime(rates_frame['time'], unit='s')

    # Display data directly
    print("\nDisplay dataframe with data")
    print(rates_frame.head(10))

如果由于某种原因,您无法获取历史数据,您可以通过以下步骤在 MetTrader5 平台上手动检索。启动您的 MetaTrader 平台,在 MetaTrader 5 窗格/面板顶部导航至 >工具,然后 >选项,您将进入图表选项。然后您必须选择要下载的图表中的柱形数量。最好选择无限柱形的选项,因为我们将处理日期,并且我们不知道在给定的时间段内有多少柱形。

之后,您现在必须下载实际数据。为此,您必须导航至 >查看,然后导航至 >交易品种,然后进入规格选项卡。根据要下载的数据类型,只需导航至 > 报价 。继续并输入您想要下载的历史数据的开始和结束日期,然后单击请求按钮下载数据并将其保存为 .csv 格式。


Jupyter Lab 上的 MetaTrader 5 数据可视化

要将 MetaTrader 5 历史数据加载到 Jupyter Lab 中,您首先需要找到下载数据的文件夹。进入 Jupyter Lab 后,导航到该文件夹以访问文件。下一步是加载数据并查看列名。检查列名对于确保正确管理数据并防止使用不正确的列名可能发生的错误非常重要。

Python 代码:

import pandas as pd

# assign variable to the historical data
file_path = '/home/int_junkie/Documents/ML/predi/XAUUSD.m_H1_2nd.csv'

data = pd.read_csv(file_path, delimiter='\t')

# Display the first few rows and column names
print(data.head())
print(data.columns)



我们的历史数据从 2024 年 1 月 2 日开始,直到当前数据。

Python 代码:

# Convert the <DATE> and <TIME> columns into a single datetime column
data['<DATETIME>'] = pd.to_datetime(data['<DATE>'] + ' ' + data['<TIME>'], format='%Y.%m.%d %H:%M:%S')

# Drop the original <DATE> and <TIME> columns
data = data.drop(columns=['<DATE>', '<TIME>'])

# Convert numeric columns from strings to appropriate float types
numeric_columns = ['<OPEN>', '<HIGH>', '<LOW>', '<CLOSE>', '<TICKVOL>', '<VOL>', '<SPREAD>']
data[numeric_columns] = data[numeric_columns].apply(pd.to_numeric)

# Set datetime as index for easier plotting
data.set_index('<DATETIME>', inplace=True)

# Let's plot the close price and tick volume to visualize the trend
import matplotlib.pyplot as plt

# Plot closing price and tick volume
fig, ax1 = plt.subplots(figsize=(12, 6))

# Close price on primary y-axis
ax1.set_xlabel('Date')
ax1.set_ylabel('Close Price', color='tab:blue')
ax1.plot(data.index, data['<CLOSE>'], color='tab:blue', label='Close Price')
ax1.tick_params(axis='y', labelcolor='tab:blue')

# Tick volume on secondary y-axis
ax2 = ax1.twinx()  
ax2.set_ylabel('Tick Volume', color='tab:green')  
ax2.plot(data.index, data['<TICKVOL>'], color='tab:green', label='Tick Volume')
ax2.tick_params(axis='y', labelcolor='tab:green')

# Show the plot
plt.title('Close Price and Tick Volume Over Time')
fig.tight_layout()
plt.show()

收盘价和分时交易量

上图显示了随时间变化的两个关键指标:

  1. 收盘价(蓝色):这代表图表上每小时的收盘价。我们可以观察到随时间推移的波动,表明黄金价格(XAU/USD)存在上涨和下跌趋势。
  2. 分时交易量(绿色):这表示每小时内价格变化的次数。分时交易量的飙升通常对应于市场活动或波动性的增加。例如,高交易量时期可能与重大价格变动相吻合,这可能预示着重要事件或市场情绪的转变。

现在让我们更深入地研究我们的数据:

1.趋势分析。

# Calculating moving averages: 50-period and 200-period for trend analysis
data['MA50'] = data['<CLOSE>'].rolling(window=50).mean()
data['MA200'] = data['<CLOSE>'].rolling(window=200).mean()

# Plot close price along with the moving averages
plt.figure(figsize=(12, 6))

# Plot close price
plt.plot(data.index, data['<CLOSE>'], label='Close Price', color='blue')

# Plot moving averages
plt.plot(data.index, data['MA50'], label='50-Period Moving Average', color='orange')
plt.plot(data.index, data['MA200'], label='200-Period Moving Average', color='red')

plt.title('Close Price with 50 & 200 Period Moving Averages')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend(loc='best')
plt.grid(True)
plt.show()


该图显示了收盘价以及 50 周期和 200 周期移动平均线:

  1. 收盘价(蓝色线):这代表了每个时间段结束时的实际价格。
  2. 50 周期移动平均线(橙色线):一个短期移动平均线,平滑了 50 个时期的价格数据。当收盘价越过这条线时,它可能预示着潜在的上涨趋势,当它穿过这条线以下时,可能预示着下跌趋势。
  3. 200 周期移动平均线(红色线):长期移动平均线,提供对整体趋势的洞察。它对价格变化的反应往往较慢,因此与 50 期移动平均线的交叉可能预示着长期趋势的重大逆转。

我们正在寻找的关键点是金叉,当 50 期移动平均线越过 200 期移动平均线上时,它可能预示着潜在的强劲看涨趋势。最后一个是死叉,当 50 期移动平均线穿过 200 期移动平均线上时,它可能预示着潜在的看跌趋势。

接下来,我们通过计算价格范围(最高价和最低价之间的差异)来分析波动性并将其可视化。

2.波动性分析。

# Calculate the price range (High - Low)
data['Price_Range'] = data['<HIGH>'] - data['<LOW>']

# Calculate Bollinger Bands
# Use a 20-period moving average and 2 standard deviations
data['MA20'] = data['<CLOSE>'].rolling(window=20).mean()
data['BB_upper'] = data['MA20'] + 2 * data['<CLOSE>'].rolling(window=20).std()
data['BB_lower'] = data['MA20'] - 2 * data['<CLOSE>'].rolling(window=20).std()

# Plot the price range and Bollinger Bands along with the close price
plt.figure(figsize=(12, 8))

# Plot the close price
plt.plot(data.index, data['<CLOSE>'], label='Close Price', color='blue')

# Plot Bollinger Bands
plt.plot(data.index, data['BB_upper'], label='Upper Bollinger Band', color='red', linestyle='--')
plt.plot(data.index, data['BB_lower'], label='Lower Bollinger Band', color='green', linestyle='--')

# Fill the area between Bollinger Bands for better visualization
plt.fill_between(data.index, data['BB_upper'], data['BB_lower'], color='gray', alpha=0.3)

# Plot the price range on a separate axis
plt.figure(figsize=(12, 6))
plt.plot(data.index, data['Price_Range'], label='Price Range (High-Low)', color='purple')

plt.title('Bollinger Bands and Price Range (Volatility Analysis)')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend(loc='best')
plt.grid(True)
plt.show()



从上面的输出中,我们完成了以下工作:

  1. 价格范围计算:我们通过从最高价格(“ <High> ”)中减去最低价格(“ <LOW> ”)来计算每个时间段的价格范围。这给出了每个小时价格变动的程度,有助于衡量该时期的波动性
  2. `data['Price-Range'] = data['<HIGH>'] - data['<LOW>'] :生成的 “Price-Rang”(价格范围)列显示了每小时内价格波动的幅度。
  3. 布林带计算:布林带指标是通过计算来了解价格波动的。` MA-20 ` 是收盘价的 20 周期移动平均线。它是布林带的中线。`BB-upper` 和 `BB-lower` 分别代表上轨和下轨。它们以 20 周期移动平均线的上下两个标准差来计算。当价格朝上轨移动时,表明市场可能超买;同样,朝下轨移动则表明市场可能超卖。
  4. 价格和布林带的可视化:收盘价(蓝色线),表示每个时间段的实际收盘价。上布林带(红色虚线)和下布林带(绿色虚线),这些线显示了围绕移动平均线形成布林带的波动带。阴影区域,布林带上下轨之间的区域呈灰色阴影,直观地表示价格预期波动的范围。
  5. 单独价格范围图:第二张图将价格范围显示为一条单独的紫色线,显示波动率随时间的变化情况。该图中较大的峰值表明波动性增加的时期。
创建强化学习模型:
    import pandas as pd
    import talib
    from stable_baselines3 import DQN
    from stable_baselines3.common.env_checker import check_env
    
    # Verify the environment
    check_env(env)
    
    # Initialize and train the DQN model
    model = DQN('MlpPolicy', env, verbose=1)
    model.learn(total_timesteps=10000)
    
    # Save the trained model
    model.save("trading_dqn_model")
    
    # Load and preprocess the data as before
    data = pd.read_csv('XAUUSD_H1_Data-V.csv', delimiter='\t')
    data['<DATETIME>'] = pd.to_datetime(data['<DATE>'] + ' ' + data['<TIME>'], format='%Y.%m.%d %H:%M:%S')
    data = data.drop(columns=['<DATE>', '<TIME>'])
    numeric_columns = ['<OPEN>', '<HIGH>', '<LOW>', '<CLOSE>', '<TICKVOL>', '<VOL>', '<SPREAD>']
    data[numeric_columns] = data[numeric_columns].apply(pd.to_numeric)
    data.set_index('<DATETIME>', inplace=True)
    
    # Calculate Bollinger Bands (20-period moving average with 2 standard deviations)
    data['MA20'] = data['<CLOSE>'].rolling(window=20).mean()
    data['BB_upper'] = data['MA20'] + 2 * data['<CLOSE>'].rolling(window=20).std()
    data['BB_lower'] = data['MA20'] - 2 * data['<CLOSE>'].rolling(window=20).std()
    
    # Calculate percentage price change and volume change as additional features
    data['Pct_Change'] = data['<CLOSE>'].pct_change()
    data['Volume_Change'] = data['<VOL>'].pct_change()
    
    # Fill missing values
    data.fillna(0, inplace=True)

    在上面的代码中,我们为强化学习(RL)模型准备财务数据,以便使用来自 “stable-baseline3” 的DQN(深度 Q 网络)算法对 XAU / USD(黄金)市场做出交易决策。它首先加载和处理历史数据,包括计算布林带(基于移动平均线和价格波动的技术指标)并添加百分比价格和交易量变化等功能。环境经过验证,并对 DQN 模型进行了 10000 个时间步的训练,之后保存该模型以供将来使用。最后,用零填充缺失的数据,以确保模型训练的顺利进行。

    import gym
    from gym import spaces
    import numpy as np
    
    class TradingEnv(gym.Env):
        def __init__(self, data):
            super(TradingEnv, self).__init__()
            
            # Market data and feature columns
            self.data = data
            self.current_step = 0
            
            # Define action and observation space
            # Actions: 0 = Hold, 1 = Buy, 2 = Sell
            self.action_space = spaces.Discrete(3)
            
            # Observations (features: Bollinger Bands, Price Change, Volume Change)
            self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(5,), dtype=np.float32)
            
            # Initial balance and positions
            self.balance = 10000  # Starting balance
            self.position = 0  # No position at the start (0 = no trade, 1 = buy, -1 = sell)
        
        def reset(self):
            self.current_step = 0
            self.balance = 10000
            self.position = 0
            return self._next_observation()
        
        def _next_observation(self):
            # Get the current market data (Bollinger Bands, Price Change, Volume Change)
            obs = np.array([
                self.data['BB_upper'].iloc[self.current_step],
                self.data['BB_lower'].iloc[self.current_step],
                self.data['Pct_Change'].iloc[self.current_step],
                self.data['Volume_Change'].iloc[self.current_step],
                self.position
            ])
            return obs
        
        def step(self, action):
            # Execute the trade based on action and update balance and position
            self.current_step += 1
            
            # Get current price
            current_price = self.data['<CLOSE>'].iloc[self.current_step]
            
            reward = 0  # Reward initialization
            done = self.current_step == len(self.data) - 1  # Check if we're done
            
            # Buy action
            if action == 1 and self.position == 0:
                self.position = 1
                self.entry_price = current_price
            
            # Sell action
            elif action == 2 and self.position == 1:
                reward = current_price - self.entry_price
                self.balance += reward
                self.position = 0
            
            # Hold action
            else:
                reward = 0
            
            return self._next_observation(), reward, done, {}
        
        def render(self, mode='human', close=False):
            # Optional: Print the current balance and position
            print(f"Step: {self.current_step}, Balance: {self.balance}, Position: {self.position}")
    
    # Create the trading environment
    env = TradingEnv(data)

    从上面的代码中,我们使用 `gym` 库定义了一个交易环境 `TradingEnv` 类,以根据历史市场数据模拟交易环境。环境允许三种可能的操作:持有、买入或卖出。它包括一个具有五个特征(布林带、百分比价格变化、交易量变化和当前交易头寸)的观察空间。代理开始时余额为 10000 个单位且无头寸。在每一步中,基于所选操作,环境更新代理的位置和余额,计算盈利交易的奖励,并前进到数据中的下一步。环境可以重置以开始新的事件或呈现交易过程的当前状态。该环境将用于训练强化学习模型。

    import gymnasium as gym
    from gymnasium import spaces
    import numpy as np
    from stable_baselines3 import DQN
    from stable_baselines3.common.env_checker import check_env
    
    # Define the custom Trading Environment
    class TradingEnv(gym.Env):
        def __init__(self, data):
            super(TradingEnv, self).__init__()
            
            # Market data and feature columns
            self.data = data
            self.current_step = 0
            
            # Define action and observation space
            # Actions: 0 = Hold, 1 = Buy, 2 = Sell
            self.action_space = spaces.Discrete(3)
            
            # Observations (features: Bollinger Bands, Price Change, Volume Change)
            self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(5,), dtype=np.float32)
            
            # Initial balance and positions
            self.balance = 10000  # Starting balance
            self.position = 0  # No position at the start (0 = no trade, 1 = buy, -1 = sell)
    
        def reset(self, seed=None, options=None):
            # Initialize the random seed
            self.np_random, seed = self.seed(seed)
            
            self.current_step = 0
            self.balance = 10000
            self.position = 0
            
            # Return initial observation and an empty info dictionary
            return self._next_observation(), {}
    
        def _next_observation(self):
            # Get the current market data (Bollinger Bands, Price Change, Volume Change)
            obs = np.array([
                self.data['BB_upper'].iloc[self.current_step],
                self.data['BB_lower'].iloc[self.current_step],
                self.data['Pct_Change'].iloc[self.current_step],
                self.data['Volume_Change'].iloc[self.current_step],
                self.position
            ], dtype=np.float32)  # Explicitly cast to float32
            return obs
        
        def step(self, action):
            self.current_step += 1
            current_price = self.data['<CLOSE>'].iloc[self.current_step]
            
            reward = 0
            done = self.current_step == len(self.data) - 1
            truncated = False  # Set to False unless there's an external condition to end the episode early
            
            # Execute the action
            if action == 1 and self.position == 0:
                self.position = 1
                self.entry_price = current_price
            
            elif action == 2 and self.position == 1:
                reward = current_price - self.entry_price
                self.balance += reward
                self.position = 0
            
            # Return next observation, reward, terminated, truncated, and an empty info dict
            return self._next_observation(), reward, done, truncated, {}
    
        def render(self, mode='human', close=False):
            print(f"Step: {self.current_step}, Balance: {self.balance}, Position: {self.position}")
        
        def seed(self, seed=None):
            self.np_random, seed = gym.utils.seeding.np_random(seed)
            return self.np_random, seed
    
    # Assuming your data is already prepared (as a DataFrame) and includes Bollinger Bands and other necessary features
    # Create the environment
    env = TradingEnv(data)
    
    # Verify the environment
    check_env(env)
    
    # Train the model using DQN
    model = DQN('MlpPolicy', env, verbose=1)
    model.learn(total_timesteps=10000)
    
    # Save the trained model
    model.save("trading_dqn_model")
    

    输出:

    模型

    然后,我们使用 “gymnasium” 来定义一个自定义交易环境进行强化学习,其中代理学习根据历史市场数据做出交易决策。该环境允许三种操作:持有、买入或卖出,并具有五种观察功能,包括布林带、百分比价格变化、成交量变化和当前仓位。代理商的起始余额为 10,000,并且没有未平仓头寸。环境中的每一步都会推动代理前进,更新其仓位、余额,并计算成功交易的奖励。使用 “stable-baseline3” 中的 “check-Env()” 函数验证环境,并对 DQN(深度 Q 网络)模型进行 10,000 个时间步长的训练,以学习最佳交易策略。训练好的模型被保存以供将来在自动交易系统中使用。

    # Unpack the observation from the reset() method
    obs, _ = env.reset()
    
    # Loop through the environment steps
    for step in range(len(data)):
        # Predict the action based on the observation
        action, _states = model.predict(obs)
        
        # Step the environment
        obs, rewards, done, truncated, info = env.step(action)
        
        # Render the environment (print the current state)
        env.render()
    
        # Check if the episode is done
        if done or truncated:
            print("Testing completed!")
            break
    

    起始净值

    期末净值

    结果表明,训练模型实施的交易策略在交易期间带来了小幅盈利,余额从 10,000 美元增加到 10,108 美元。虽然这表明该模型能够识别有利可图的交易,但 108 美元的利润率(1.08% 的收益)相对较低。

    结果表明,该模型正在进行谨慎或低频交易,或者可能表明该策略没有完全优化以获得更高的回报。进一步的评估,包括更长的测试期或对模型参数(如奖励函数、特征选择或交易执行逻辑)的调整,可以帮助提高模型的性能。考虑交易成本和风险管理等因素也很重要,以确保该策略随着时间的推移保持盈利。

    将所有内容放在 MQL5 中

    我们将把 MQL5 连接到将运行我们训练的模型的 Python 脚本,我们必须在 MQL5 和 Python 之间建立一个通信渠道。在我们的例子中,我们将使用一个常用的套接字服务器。
    //+------------------------------------------------------------------+
    //|                                                   EnhancedML.mq5 |
    //|                                  Copyright 2024, MetaQuotes Ltd. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2024, MetaQuotes Ltd."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    
    //+------------------------------------------------------------------+
    //|                          Includes                                |
    //+------------------------------------------------------------------+
    #include <WinAPI\winapi.mqh>
    #include <Trade\Trade.mqh>
    CTrade              trade;

    首先,我们包括用于系统级操作的 Windows API 库(“winapi.mqh”)和用于交易管理的交易库(“trade.mqh”)。然后我们声明一个(`CTrade`)类的实例,名为 trade。

    //+------------------------------------------------------------------+
    //|                          Global Vars                             |
    //+------------------------------------------------------------------+
    int stopLoss = 350;
    int takeProfit = 500;
    
    string Address = "127.0.0.1";
    int port = 9999;
    int socket = SocketCreate();
    
    double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

    我们将 “Address” 设置为“127.0.0.1”(本地主机),将 “port” 设置为“9999”,我们将使用它进行套接字通信。`SocketCreate()` 函数初始化一个套接字并将套接字句柄存储在 `socket` 变量中,从而允许与 Python 服务器通信。

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit(){
    
        if (!SocketConnect(socket, Address, port, 1000)){  
            Print("Successfully connected to ", Address, ":", port);
        } else {
            Print("Connection to ", Address, ":", port, " failed, error ", GetLastError());
            return INIT_FAILED;
        }
    
       return(INIT_SUCCEEDED);
    }

    ` SocketConnect() ` 函数尝试将创建的套接字连接到给定地址(本地主机)和端口 `9999` 的 Python 服务器。我们的超时时间(以毫秒为单位)是 “1000”。

    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick(){
       
       
       uint len=SocketIsReadable(socket);
    
       char buffer[16];
       int bytes = SocketRead(socket, buffer, len, 23);
       
       if (bytes > 0){
       
          string action_str = CharArrayToString(buffer);
          
          int action = StringToInteger(action_str);
          //int action = atoi(buffer);
          
          // Execute a trade based on action
          if(action == 1){
             //buy trade
             MBuy();
             Print("Buy action received...");
          } else if(action == 2){
             //sell trade
             MSell();
             Print("Sell action received...");
          }
       }
       
    }

    我们的 MQL5 中的 `OnTick()` 函数旨在通过套接字连接处理每个市场报价中传入的交易指令。它首先使用“SocketIsReadable()”检查套接字上是否有可用数据,然后返回数据的长度。如果存在数据,`SocketRead()` 函数会将数据读入缓冲区,并将成功读取的字节数存储在 `bytes` 中。如果已收到数据,则缓冲区将转换为字符串,然后转换为整数(action)。根据 `action` 的值,该函数执行相应的交易:如果 `action == 1`,则通过调用 `MBuy()` 执行买入交易,如果 `action == 2`,则通过调用 `MSell()` 触发卖出交易。每次交易行为之后,print 语句都会记录收到的行为(买入或卖出)。本质上,该函数通过套接字监听买入或卖出命令并自动执行相应的交易。

    //+------------------------------------------------------------------+
    //|                        Buy Function                              |
    //+------------------------------------------------------------------+
    void MBuy(){
    
       static int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
    
       double Lots = 0.02;
       double sl = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID) - stopLoss, digits);
       double tp = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK) + takeProfit * _Point, digits);
       trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, Lots, Ask, sl, tp);
    }

    开启买入交易的函数。

    //+------------------------------------------------------------------+
    //|                         Sell Function                            |
    //+------------------------------------------------------------------+
    void MSell(){
       static int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
    
       double Lots = 0.02;
       double sl = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK) + stopLoss, digits);
       double tp = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID) - takeProfit * _Point, digits);
       trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, Lots, Bid, sl, tp);
    }

    开启卖出交易的函数。


    Python Socket 服务器脚本(交易模型服务器)

    我们的 Python 脚本将加载训练好的模型,并设置一个套接字服务器来监听来自 MQL5 的连接。当它收到数据时,它会做出预测并发回交易行为。

    import socket
    import numpy as np
    from stable_baselines3 import DQN
    
    # Load the trained model
    model = DQN.load("trading_dqn_model")
    
    # Set up the server
    HOST = '127.0.0.1'  # Localhost (you can replace this with your IP)
    PORT = 9999         # Port to listen on
    
    # Create a TCP/IP socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((HOST, PORT))
    server_socket.listen(1)
    
    print(f"Server listening on {HOST}:{PORT}...")
    
    while True:
        # Wait for a connection
        client_socket, client_address = server_socket.accept()
        print(f"Connection from {client_address}")
        
        # Receive data from MQL5 (price data sent by EA)
        data = client_socket.recv(1024).decode('utf-8')
        
        if data:
            print(f"Received data: {data}")
            
            # Convert received data to a numpy array
            observation = np.fromstring(data, sep=',')  # Assumes comma-separated price data
    
            # Make prediction using the model
            action, _ = model.predict(observation)
            
            # Send the predicted action back to MQL5
            client_socket.send(str(action).encode('utf-8'))
        
        # Close the client connection
        client_socket.close()
    

    将 Python 脚本保存为 “trading-model-server.py” 或您选择的任何名称。打开终端或命令提示符,导航到保存模型和 “trading-model-server.py” 的目录,然后运行以下命令建立连接。

    python trading_model_server.py
    


    结论

    总之,我们开发了一个全面的交易系统,将机器学习与 MQL5 集成在一起,根据历史数据自动做出交易决策。我们首先加载和预处理 XAU/USD 历史数据,计算布林带,并实现价格和数量变化等其他关键功能。使用强化学习,特别是深度 Q 网络(DQN),我们训练了一个模型,根据数据中的模式预测买卖行为。然后,训练好的模型通过套接字通信系统连接到 MQL5,允许交易平台和我们基于 Python 的决策模型之间进行实时交互。这使我们能够根据模型的预测自动执行交易,使整个系统成为算法交易的强大工具。

    这种增强的数据可视化和机器学习集成可以通过提供更深入的见解和更明智的决策,使交易者受益匪浅。通过分析市场趋势、波动性和关键模式,该系统可以确定交易的最佳进入和退出点。基于数据驱动模型的交易执行自动化减少了人为错误和情绪偏差,从而实现了更一致和更具战略性的交易。总体而言,这种方法为交易者提供了一种复杂的工具,该工具利用历史数据来提高绩效,同时通过自动化重复的交易任务来节省时间。

    本文由MetaQuotes Ltd译自英文
    原文地址: https://www.mql5.com/en/articles/16083

    附加的文件 |
    Enhanced.ipynb (2101.04 KB)
    EnhancedML.mq5 (3.68 KB)
    XAUUSD_H1_2nd.csv (281.65 KB)
    最近评论 | 前往讨论 (4)
    amrhamed83
    amrhamed83 | 25 10月 2024 在 13:58

    你从哪里将数据从 mt5 发送到 python?

    我没有运行代码,但似乎缺少.....。

    Stanislav Korotky
    Stanislav Korotky | 25 10月 2024 在 22:28
    我在这篇文章中根本没有看到 "增强数据可视化"。标题具有误导性。
    Hlomohang John Borotho
    Hlomohang John Borotho | 28 10月 2024 在 21:46
    amrhamed83 #:

    从哪里将数据从 mt5 发送到 python?

    我没有运行代码,但似乎缺少.....。

    如果您指的是信号数据,其工作原理是我们有一个连接到 MetaTrader5 的 python 服务器,其中包含训练有素的模型,文章中的 python 服务器运行在本地主机上。
    HOST = '127.0.0.1'  # Localhost (you can replace this with your IP)
    PORT = 9999         # Port to listen on
    Too Chee Ng
    Too Chee Ng | 18 12月 2024 在 12:33
    感谢您的这篇文章。很好的框架。
    价格行为分析工具包开发系列(第4部分):分析预测型EA 价格行为分析工具包开发系列(第4部分):分析预测型EA
    我们不再局限于仅在图表上查看分析后的指标,而是将视野拓展至更广阔的范畴,其中包括与Telegram的集成。这一增强功能使得重要结果能够通过Telegram应用程序直接发送至您的移动设备。请随我们一同在本篇文章中探索这一过程。
    金融建模中合成数据的生成式对抗网络(GAN)(第 1 部分):金融建模中的 GAN 与合成数据概述 金融建模中合成数据的生成式对抗网络(GAN)(第 1 部分):金融建模中的 GAN 与合成数据概述
    本文向交易者介绍产生合成金融数据的生成式对抗网络(GAN),解决模型训练中的数据限制。它涵盖了 GAN 基础知识、python 和 MQL5 代码实现,以及实际的金融应用,令交易者能够通过合成数据强化模型的准确性和健壮性。
    群体自适应矩估计(ADAM)优化算法 群体自适应矩估计(ADAM)优化算法
    本文介绍了将广为人知且广受欢迎的ADAM梯度优化方法转变为群体算法的过程,并介绍了通过引入混合个体对其进行改进的方案。这种新方法能够利用概率分布创建融合了成功决策要素的智能体。关键创新点在于形成了群体混合个体,这些个体能够自适应地积累来自最具潜力解决方案的信息,从而提高了在复杂多维空间中的搜索效率。
    通过成交量洞察交易:趋势确认 通过成交量洞察交易:趋势确认
    增强型趋势确认技术结合了价格行为、成交量分析和机器学习,用以识别真实的市场行情。该技术要求价格突破和成交量激增(高于平均值50%)这两个条件同时满足以验证交易信号,同时使用一个LSTM神经网络进行附加确认。该系统采用基于ATR(平均真实波幅)的仓位调整和动态风险管理,使其能够适应不同的市场条件,同时过滤掉虚假信号。