
价格行为分析工具包开发(第九部分):外部数据流
概述
金融市场可能十分复杂,交易者和分析师在准确处理和解读数据方面常常面临挑战。为应对这些挑战,人们开发了各种库来简化市场分析,每种库都旨在以符合特定目标的方式处理数据。虽然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:服务器的响应内容(通常为分析结果)。
图例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会解析该响应以提取关键数据,例如:
- 交易信号:交易指令(如“买入”或“卖出”)。
- 平均价格:通过分析得出的平均价格。
- 平均成交量:交易的成交平均量。
- 信号说明:对生成该交易信号的原因解释。
该函数使用StringFind和StringSubstr从响应字符串中提取这些值。
如果自上次更新以来交易信号发生了变化(当前信号 ≠前一次信号(lastSignal)),则:
1)更新lastSignal和lastSignalTime变量。
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)将执行以下操作:
- 更新lastSigna和lastSignalTime变量。
- 创建一个包含交易信号、平均价格、平均成交量及信号说明的字符串摘要。
- 将该摘要以注释形式显示在图表上,并打印至日志。
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
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。



