English Русский Deutsch 日本語
preview
价格行为分析工具包开发(第九部分):外部数据流

价格行为分析工具包开发(第九部分):外部数据流

MetaTrader 5交易系统 |
21 0
Christian Benjamin
Christian Benjamin

概述

金融市场可能十分复杂,交易者和分析师在准确处理和解读数据方面常常面临挑战。为应对这些挑战,人们开发了各种库来简化市场分析,每种库都旨在以符合特定目标的方式处理数据。虽然MQL5库常用于创建交易策略和指标,但外部库(如Python的数据分析工具)则为更高级、更深入的分析提供了额外的资源。

在先前的文章中,我主要聚焦于价格行为与数据分析,重点探讨了如何通过MQL5智能交易系统(EA)的计算与指标处理来生成交易信号。然而,这些文章的分析范围仅限于MQL5框架之内。本文则标志着一次转变,将引入专为高级数据分析设计的外部库进行整合。借助Python库Pandas,我们能够为交易者开辟新的分析路径,提供更广泛的分析选项,以满足多样化的需求。

这种方法并非要取代MQL5,而是将其作为该系统的核心。MQL5 EA充当桥梁角色,实现与外部库和服务器的交互,从而构建一个更为稳健和灵活的分析框架。需强调的是,本文仅仅是探索高级分析的起点,我期待在未来的讨论中呈现更全面深入的见解与技巧。

请看一下我们将如何着手完成这项任务:



策略概述

该系统的主要目标是利用Python的Pandas库的数据解析功能生成交易信号。在本节中,我们将深入探讨系统如何执行核心逻辑。整个交互过程发生在MQL5 EA与Python之间,在信号最终显示在图表上之前,中间会经历多个处理环节。让我们按照以下步骤来了解系统的工作原理。

1. MQL5 EA向Python传输数据:

  • MQL5 EA收集前10个交易日的最高价、最低价、开盘价、收盘价和成交量数据。 
  • 将数据发送至Python服务器。 
  • 将数据格式化为CSV字符串,并通过HTTP POST请求发送至Python服务器。

2. Python端处理:

  • Python接收数据,并使用Pandas等库对接收到的数据进行处理。 
  • 分析数据以生成交易信号、平均价格和成交量,并生成相应的解释说明。

3. Python向EA返回结果:

  • Python通过HTTP响应将生成的信号、平均价格、成交量和解释说明发送回MQL5 EA。

4. MQL5 EA处理:

  • MQL5 EA接收并解析响应,从响应中提取信号、平均价格、平均成交量和解释说明。 
  • 如果信号发生变化,则更新图表,显示新的信号。

让我们参考以下流程图以获取更深入的理解。


集成流程

图例1. 逻辑图



Python

Python是一种功能多样的编程语言,以其简洁性和广泛的应用领域而著称。它常用于数据分析、机器学习、Web开发以及自动化等众多任务。在本系统中,Python在执行高级数据分析方面发挥着关键作用,特别是通过诸如Pandas等库,这些库提供了高效的数据操作和分析工具。Python还搭建了一个服务器,用于MQL5与其库之间的交互。通过利用Python处理复杂的数据集,系统能够基于历史市场数据生成交易信号,并将这些信号传递给MQL5 EA,以辅助实时交易决策。 

我将一步步引导您完成Python的安装、脚本创建及运行过程。

  • 访问官方Python网站,下载Python安装程序。
  •  运行安装程序

重要提示:在点击“立即安装”之前,请务必勾选“将Python添加到PATH”选项。这样,从命令行运行Python会更加方便。

  •  完成安装

安装程序将启动安装流程。然后等待完成。安装完毕后,点击“关闭”。

  •  验证安装

打开命令提示符(按下Windows + R键,输入cmd,然后按Enter键)。输入python --version,并按Enter键。如果Python安装正确,您应该能看到Python的版本号(例如,Python 3.x.x)。

成功安装Python后,接下来考虑安装Flask和Pandas。Flask是一个轻量级的Python Web框架,用于构建Web应用程序。它设计简洁、灵活且易于使用。Flask被用来搭建一个简单的Web服务器,实现MQL5 EA与Python数据分析工具之间的通信。EA通过HTTP请求将数据发送到Flask,Flask使用Python库(在此例中为Pandas)处理数据,并将交易信号返回给EA。

要在命令提示符中安装Flask和Pandas,请按照以下步骤操作:

打开命令提示符

  • 按下Windows + R键,输入cmd,然后再按Enter键。

确保pip(Python包安装器)已安装完成

  • 首先,通过运行以下命令检查pip是否已安装:

pip --version

  • 如果pip已安装,您将看到版本号。如果未安装,您可以按照以下步骤进行安装。PIP通常与Python一起自动安装。如果PIP未安装,请下载get-pip.py,并使用命令python get-pip.py运行它。

安装Flask

  • 要在命令提示符中安装Flask,请运行以下命令:

pip install Flask

  • 等待安装完成。安装Flask以供使用。

安装Pandas

  • 要安装Pandas,请运行以下命令:

pip install pandas

  • 同样,等待安装完成。

验证安装

  • 安装完两个包后,您可以通过运行以下命令来验证安装结果:

python -c "import flask; print(flask.__version__)"

python -c "import pandas; print(pandas.__version__)"

  • 这之后应该会打印出已安装的Flask和Pandas版本,从而确认它们已成功安装。

现在,您可以着手创建Python脚本。就我个人而言,我更倾向于使用Notepad++来完成此项任务。要创建脚本,请打开Notepad++,新建一个文件,并从“语言”菜单中选择Python作为编程语言。编写完脚本后,将其保存在一个易于查找的目录中。请确保将文件保存为.py扩展名,以此标识它为Python脚本。

Python脚本

import pandas as pd
import flask
from flask import request, jsonify

app = flask.Flask(__name__)
app.config["DEBUG"] = True

@app.route('/analyze', methods=['POST'])
def analyze_csv():
    try:
        # Read CSV data from the POST request
        csv_data = request.data.decode('utf-8')

        # Write the CSV data to a file (optional, for debugging)
        with open('received_data.csv', 'w') as file:
            file.write(csv_data)

        # Load the CSV data into a DataFrame
        from io import StringIO
        data = StringIO(csv_data)
        df = pd.read_csv(data)

        # Ensure the CSV has the correct columns
        required_columns = ['date', 'prev_high', 'prev_low', 'prev_open', 'prev_close', 'prev_volume']
        for column in required_columns:
            if column not in df.columns:
                return jsonify({"error": f"Missing column: {column}"}), 400

        # Print the received metrics for debugging
        print("Received metrics:")
        print(df)

        # Perform analysis (Example: Calculate average price and volume)
        df['average_price'] = (df['prev_high'] + df['prev_low'] + df['prev_open'] + df['prev_close']) / 4
        average_price = df['average_price'].mean()  # Average of all the average prices
        average_volume = df['prev_volume'].mean()  # Average volume

        # Print the computed averages
        print(f"Average Price: {average_price}")
        print(f"Average Volume: {average_volume}")

        # Create a trading signal based on a simple rule
        last_close = df['prev_close'].iloc[-1]
        if last_close > average_price:
            signal = "BUY"
            signal_explanation = f"The last close price ({last_close}) is higher than the average price ({average_price})."
        else:
            signal = "SELL"
            signal_explanation = f"The last close price ({last_close}) is lower than the average price ({average_price})."

        # Print the signal and explanation
        print(f"Generated Signal: {signal}")
        print(f"Signal Explanation: {signal_explanation}")

        # Return the signal as JSON
        return jsonify({
            "signal": signal,
            "average_price": average_price,
            "average_volume": average_volume,
            "signal_explanation": signal_explanation
        })

    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    app.run(host='189.7.6.8', port=5877)

要运行脚本,请在电脑上打开命令提示符。

运行以下命令:

cd C:\Users\pathway to your python script folder

接着又运行以下命令:

python filename.py

执行脚本时,请使用您为脚本指定的确切名称。一旦脚本开始运行,它将显示端口正在积极监听的状态。

 Running on http://189.7.6.8:5877


主函数

初始化(OnInit

当EA在MetaTrader平台首次初始化时,该函数便会运行。它用于设置EA所需的任何资源或配置。在此情况下,它仅向日志打印一条消息,表明EA已准备好开始与Python服务器进行交互。

int OnInit()
{
   Print("Expert initialized. Ready to send data to Python.");
   return(INIT_SUCCEEDED);
}

返回INIT_SUCCEEDED值表示初始化成功。

反初始化(OnDeinit)

当EA被移除或MetaTrader平台关闭时,会触发此函数。它通常用于执行清理操作,例如释放资源或关闭已打开的文件。在此情况下,它仅打印一条消息,表明EA已完成反初始化且不再处于活动状态。

void OnDeinit(const int reason)
{
   Print("Expert deinitialized.");
}

OnTick (核心功能)

这是EA的主函数,每当市场条件发生变化(即每个新tick到达时)都会执行该函数。

void OnTick()
{
   // Check if enough time has passed since the last signal update
   if(TimeCurrent() - lastSignalTime < signalInterval)
   {
      return;  // Skip if it's too soon to update
   }

   // Collect data and prepare CSV for Python
   string csvData = "date,prev_high,prev_low,prev_open,prev_close,prev_volume\n";

   // Get the previous trend data for the last `trendDays`
   for(int i = 1; i <= 10; i++)  // You can adjust the trendDays here
   {
      datetime prevDate = iTime(Symbol(), PERIOD_D1, i);
      double prevHigh = iHigh(Symbol(), PERIOD_D1, i);
      double prevLow = iLow(Symbol(), PERIOD_D1, i);
      double prevOpen = iOpen(Symbol(), PERIOD_D1, i);
      double prevClose = iClose(Symbol(), PERIOD_D1, i);
      long prevVolume = iVolume(Symbol(), PERIOD_D1, i);

      csvData += StringFormat("%s,%.5f,%.5f,%.5f,%.5f,%ld\n",
                              TimeToString(prevDate, TIME_DATE | TIME_MINUTES),
                              prevHigh, prevLow, prevOpen, prevClose, prevVolume);
   }

   // Save data to CSV file
   string fileName = StringFormat("%s_analytics.csv", Symbol());
   int fileHandle = FileOpen(fileName, FILE_WRITE | FILE_CSV | FILE_ANSI);
   if(fileHandle != INVALID_HANDLE)
   {
      FileWriteString(fileHandle, csvData);
      FileClose(fileHandle);
      Print("CSV file created: ", fileName);
   }
}

其还会执行以下操作:

  • 信号间隔检查 :EA首先使用 TimeCurrent()函数检查自上次信号更新以来是否已过去足够的时间。如果尚未过去足够的时间,则跳过处理。
  • 数据收集: EA收集过去10天(若修改循环中的数值,可收集更多)的市场数据,包括:前一日的最高价、最低价、开盘价、收盘价和成交量。
  • 数据格式化: 随后,EA将这些数据格式化为CSV格式,以便轻松传输至Python服务器。 
  • CSV文件保存:数据以<symbol>_analytics.csv为文件名保存为.csv文件至磁盘。若文件创建和写入成功,则打印成功消息。

向Python服务器发送HTTP请求(WebRequest

string headers = "Content-Type: application/json\r\n";
char result[];
string resultHeaders;
int responseCode = WebRequest(
    "POST",                  // HTTP method
    pythonUrl,               // URL
    headers,                 // Custom headers
    timeout,                 // Timeout in milliseconds
    data,                    // Data to send
    result,                  // Response content
    resultHeaders            // Response headers
);

if(responseCode == 200)
{
    string response = CharArrayToString(result);
    Print("Received response: ", response);
}
else
{
    Print("Error: HTTP request failed with code ", responseCode);
}

在将数据转化为CSV格式后,EA会通过HTTP POST请求将该数据发送至Python服务器。

  • 请求头: 将Content-Type请求头设置为application/json,以此告知服务器所发送的数据为JSON格式。
  • WebRequest:使用WebRequest函数向Python服务器发送HTTP POST请求。该函数返回:

1) responseCode:HTTP响应代码(例如,200表示成功)。

2) result:服务器的响应内容(通常为分析结果)。

WebRequest

图例2. WebRequest流程图

  • 若请求成功(responseCode == 200),则将响应内容从字符数组转换为字符串,并打印成功消息。若请求失败,则显示错误消息。

解析并展示响应内容

if(responseCode == 200)
{
    string signal = "";
    string avgPrice = "";
    string avgVolume = "";
    string explanation = "";

    // Extract signal, avgPrice, avgVolume, and explanation from the response
    int signalStart = StringFind(response, "\"signal\":");
    int signalEnd = StringFind(response, "\"average_price\":");
    int explanationStart = StringFind(response, "\"signal_explanation\":");
    int avgPriceStart = StringFind(response, "\"average_price\":");
    int avgVolumeStart = StringFind(response, "\"average_volume\":");

    if(signalStart != -1 && signalEnd != -1)
    {
        signal = StringSubstr(response, signalStart + 10, signalEnd - signalStart - 12);
    }

    if(explanationStart != -1)
    {
        explanation = StringSubstr(response, explanationStart + 23, StringFind(response, "\"", explanationStart + 23) - (explanationStart + 23));
    }

    if(avgPriceStart != -1)
    {
        avgPrice = StringSubstr(response, avgPriceStart + 16, StringFind(response, "\"", avgPriceStart + 16) - (avgPriceStart + 16));
    }

    if(avgVolumeStart != -1)
    {
        avgVolume = StringSubstr(response, avgVolumeStart + 18, StringFind(response, "\"", avgVolumeStart + 18) - (avgVolumeStart + 18));
    }

    // Update the chart if the signal has changed
    if(signal != lastSignal)
    {
        lastSignal = signal;
        lastSignalTime = TimeCurrent();  // Update last signal time
        string receivedSummary = "Signal: " + signal + "\n" +
                                 "Avg Price: " + avgPrice + "\n" +
                                 "Avg Volume: " + avgVolume + "\n" +
                                 "Explanation: " + explanation;
        Print("Received metrics and signal: ", receivedSummary);
        Comment(receivedSummary);  // Display it on the chart
    }
}

 在接收到来自Python服务器的响应后,EA会解析该响应以提取关键数据,例如:

  • 交易信号:交易指令(如“买入”或“卖出”)。
  • 平均价格:通过分析得出的平均价格。
  • 平均成交量:交易的成交平均量。
  • 信号说明:对生成该交易信号的原因解释。

该函数使用StringFindStringSubstr从响应字符串中提取这些值。

如果自上次更新以来交易信号发生了变化(当前信号 ≠前一次信号(lastSignal)),则:

1)更新lastSignallastSignalTime变量。

2)使用Comment()函数在图表上以注释形式显示新信号、平均价格、成交量和信号说明。

信号的更新与显示

此部分集成在之前的步骤中,用于更新信号并在图表上显示出来。

if(signal != lastSignal)
{
    lastSignal = signal;
    lastSignalTime = TimeCurrent();  // Update last signal time
    string receivedSummary = "Signal: " + signal + "\n" +
                             "Avg Price: " + avgPrice + "\n" +
                             "Avg Volume: " + avgVolume + "\n" +
                             "Explanation: " + explanation;
    Print("Received metrics and signal: ", receivedSummary);
    Comment(receivedSummary);  // Display it on the chart
}

 若交易信号发生改变(即与前一次信号不同),智能交易系统(EA)将执行以下操作:

  • 更新lastSignalastSignalTime变量。
  • 创建一个包含交易信号、平均价格、平均成交量及信号说明的字符串摘要。
  • 将该摘要以注释形式显示在图表上,并打印至日志。

CharArrayToString(实用工具函数)

string CharArrayToString(char &arr[])
{
    string result = "";
    for(int i = 0; i < ArraySize(arr); i++)
    {
        result += StringFormat("%c", arr[i]);
    }
    return(result);
}

该实用工具函数用于将从HTTP响应中接收到的字符数组转换为字符串。它会遍历字符数组中的每个元素,并将对应的字符追加到结果字符串中。

这些步骤均经过精心设计,以处理过程中的特定环节:收集数据、将其发送至Python服务器、接收分析结果,以及用交易信号更新图表。此方法确保了EA能够自主运行,收集相关市场数据,并根据基于Python的分析结果做出决策。


成果

第一步是确认您的Python脚本正在运行,并在必需的服务器上处于主动监听状态。有关设置和运行脚本的详细说明,请参阅上文的Python部分。如果其处于主动监听状态,应该显示: 
Running on http://189.7.6.8:5877

请注意,上述提及的API和主机并非实际使用的,而是为教学目的生成的。接下来,我们开始启动MQL5 EA。如果MQL5与Python服务器之间的连接成功建立,您将在图表的“Experts“选项卡中看到日志消息。此外,在命令提示符中运行的Python脚本将显示接收到的指标。

命令提示符将显示的内容如下:

189.7.6.8 - - [21/Jan/2025 10:53:44] "POST /analyze HTTP/1.1" 200 -
Received metrics:
                date  prev_high  prev_low  prev_open  prev_close  prev_volume
0   2025.01.20 00:00    868.761   811.734    826.389     863.078      83086.0
1   2025.01.19 00:00    856.104   763.531    785.527     826.394      82805.0
2   2025.01.18 00:00    807.400   752.820    795.523     785.531      82942.0
3   2025.01.17 00:00    886.055   790.732    868.390     795.546      83004.0
4   2025.01.16 00:00    941.334   864.202    932.870     868.393      83326.0
5   2025.01.15 00:00    943.354   870.546    890.620     932.876      83447.0
6   2025.01.14 00:00    902.248   848.496    875.473     890.622      83164.0
7   2025.01.13 00:00    941.634   838.520    932.868     875.473      82516.0
8   2025.01.12 00:00    951.350   868.223    896.455     932.883      83377.0
9   2025.01.11 00:00    920.043   857.814    879.103     896.466      83287.0
10               NaN        NaN       NaN        NaN         NaN          NaN

上述信息将供 pandas 库用于数据分析和交易信号生成。第十天的数据显示为“NaN”(非数字值),这是因为该日尚未收盘,这意味着主要依赖于前几日获取的数据值进行分析。不过,分析时也纳入了第十天当前的价格水平(尽管这些数据尚不完整)。以下是在命令提示符(CMD)中由pandas显示的分析日志和结果:

Average Price: 865.884525
Average Volume: 83095.4
Generated Signal: SELL
Signal Explanation: The last close price (nan) is lower than the average price (865.884525).

MetaTrader 5将显示以下内容:

我们先从查看“Experts”选项卡中的日志记录开始。请参考以下内容查看所获得的结果。

2025.01.21 10:50:28.106 External Flow (Boom 300 Index,D1)       CSV file created: Boom 300 Index_analytics.csv
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)       Received response: {
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)         "average_price": 865.884525,
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)         "average_volume": 83095.4,
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)         "signal": "SELL",
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)         "signal_explanation": "The last close price (nan) is lower than the average price (865.884525)."

结果也将显示在图表上,并且根据输入参数中指定的超时设置,该过程将重复执行。

图表显示

图例3. 显示结果

以下是一张根据生成的交易信号和额外分析进行操作并实现盈利的交易图表。该交易显示在M1(1分钟)时间框架下,以提高清晰度。

盈利交易

图例4. 已执行的交易



结论

在阐述了利用诸如pandas等外部库实施高级分析的具体步骤后,我相信已经为开发更先进的价格走势与市场分析工具奠定了坚实的基础。我鼓励每位交易者将此视为了解市场预期走势的全面指南。然而,为达到最优交易执行效果,请结合运用您熟悉的其他策略。我们诚挚欢迎您提出反馈与意见,以便我们持续开发更专业的市场分析高级工具。

日期工具名 描述版本 更新 备注
01/10/24图表展示器以重影效果覆盖前一日价格走势的脚本1.0初始版本Lynnchris工具箱的第一个工具
18/11/24分析评论以表格形式提供前一日的信息,并预测市场的未来方向1.0初始版本Lynnchris工具箱的第二个工具
27/11/24分析大师每两小时定期更新市场指标 1.01第二个版本Lynnchris工具箱的第三个工具
02/12/24分析预测 集成Telegram通知功能,每两小时定时更新市场指标1.1第三个版本工具数4
09/12/24波动率导航仪该EA通过布林带、RSI和ATR三大指标综合分析市场状况1.0初始版本工具数5
19/12/24均值回归信号收割器 运用均值回归策略分析市场并提供交易信号 1.0 初始版本 工具数6 
9/01/2025 信号脉冲 多时间框架分析器1.0 初始版本 工具数7 
17/01/2025 指标看板 带分析按钮的控制面板 1.0 初始版本工具数8 
21/01/2025外部数据流通过外部库进行分析1.0 初始版本工具数9 

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

附加的文件 |
External_Flow.mq5 (6.72 KB)
DeepANALYTICS.py (2.48 KB)
重新定义MQL5与MetaTrader 5指标 重新定义MQL5与MetaTrader 5指标
MQL5中一种创新的指标信息收集方法,使开发者能够向指标传递自定义输入参数以进行即时计算,从而实现了更灵活、更高效的数据分析。这种方法在算法交易中尤为实用,因为它能突破传统限制,增强对指标所处理信息的掌控力。
开发回放系统(第 75 部分):新 Chart Trade(二) 开发回放系统(第 75 部分):新 Chart Trade(二)
在本文中,我们将讨论 C_ChartFloatingRAD 类。这就是 Chart Trade 发挥作用的原因。然而,解释并未就此结束,我们将在下一篇文章中完成它,因为这篇文章的内容相当广泛,需要深入理解。此处提供的内容仅用于教育目的。在任何情况下,除了学习和掌握所提出的概念外,都不应出于任何目的使用此应用程序。
新手在交易中的10个基本错误 新手在交易中的10个基本错误
新手在交易中会犯的10个基本错误: 在市场刚开始时交易, 获利时不适当地仓促, 在损失的时候追加投资, 从最好的仓位开始平仓, 翻本心理, 最优越的仓位, 用永远买进的规则进行交易, 在第一天就平掉获利的仓位,当发出建一个相反的仓位警示时平仓, 犹豫。
价格行为分析工具包开发(第八部分):指标看板 价格行为分析工具包开发(第八部分):指标看板
作为价格行为分析领域最强大的工具之一,指标看板(Metrics Board)旨在通过一键操作简化市场分析流程,实时提供关键市场指标数据。每个功能按钮均对应特定的功能,无论是分析高/低趋势、交易量还是其他关键指标。该工具能在您最需要的时候提供精准、实时的数据。让我们通过本文更深入地了解它的功能。