简介
本文会讲述如何生成一份 HTML 文件格式的交易结果报告(利用“EA 交易”、指标或脚本),并通过 FTP 将其上传到 WWW 服务器。赫兹量化还会考虑以短消息形式向手机发送交易事件通知。
想要更自如地阅读本文内容,建议读者熟悉 HTML (超文本标记语言)知识。
要实施报告上传,赫兹量化需要一个可以通过 FTP 接受数据的 WWW 服务器(可以是任何计算机)。而要实现接收短消息形式的交易事件通知,我们需要一个电子邮箱 - 短消息的网关(大多数移动运营商和第三方组织都提供该服务)。
1. 创建报告并通过 FTP 发送
我们来创建一个 MQL5 程序,并利用它来生成一份交易报告,再将报告通过 FTP 协议发送出去。首先,赫兹量化将其制作为脚本。将来我们能用它作为一个成品块,插入到“EA 交易”和指标中。比如说,在“EA 交易”中,您可以将此程序块作为 Trade 或 Timer 事件处理程序,于交易请求后运行此块,或是为 ChartEvent 事件设定一些动作。而在指标中,您则可以将此块加入到 Timer 或 ChartEvent 事件处理程序中。
程序创建的报告示例,如图 1、2、3 所示。或者,您也可以通过本文末尾处的链接下载该报告。
图 1. 报告示例 - 交易与仓位表
图 2. 报告示例 - 平衡图
图 3. 报告示例 - 当前工具的价格图表
交易与仓位表(图 1)中,为方便起见,所有交易都被划分成仓位。该表的左侧,会显示进入市场(持仓和添加)的交易量、时间和价格。表右侧显示的则是退出市场(部分或完全平仓)的上述参数。根据 in/out (买入/卖出),交易为分两个部分 - 一个平仓,下一个开仓。
交易与仓位表的下方是平衡图表(横轴 - 时间),而其底部则是当前工具价格图表。
该程序会在 MetaTarder5_istall_dir\MQL5\Files 文件夹中创建 "report.html"、"picture1.gif" 和 "picture2.gif" 文件(html 格式报告文件、平衡图表与价格图表的图像文件)。而且终端设置中的 FTP 发布已启用 - 它会向指定服务器发送上述三种文件。此外,赫兹量化还需要两种文件 - 带有指向持仓方向箭头的图像 - 买入或卖出("buy.gif" 与 "sell.gif")。您可以采用这些图像(下载链接在文末),也可以利用任何图形编辑器自行绘制。而这两个文件也要放到 WWW 服务器中与 "report.html" 文件相同的文件夹。
作为输入参数,该程序接受报告生成周期的开始与结束时间。本例中,报告周期的结束为当前时间,用户选择报告周期的变体:整个周期、昨天、上周、上月或去年。
简单说说我们创建报告的方式。所有可用的交易历史都会请求交易服务器。获取到的成交会被一个接一个地处理。deal_status[] 数组会存储交易是否被处理的相关信息。该数组的元素索引,就是从交易服务器交易列表中接收到的交易编号。而元素的值则如下阐释:0 - 交易尚未处理,1 - 交易已被部分处理 (in/out),127 - 交易处理完毕(其它值未被使用,留作后用)。
symb_list[] 数组包含交易得以执行的金融工具名称的列表,而 lots_list[] 数组则包含交易处理时每个工具的开仓交易量。交易量正值对应的是买入持仓,而负值则对应着卖出持仓。如果交易量等于零,则意味着该工具没有敞口仓位。如果交易处理期间出现了未于列表中(symb_list[] 数组中)出现的金融工具 - 则将其添加到那里,且金融工具的编号(symb_total 变量)以 1 为增量增长。
根据每个交易处理过程,每一个后续交易都利用相同的金融工具进行分析,直到平仓或买入/卖出。只有 deal_status[] 数组值小于 127 的那些交易会被分析。交易处理之后,对应的 deal_status[] 数组元素即被赋值为 127,如果交易为仓位 in/out,则赋值 1。如果开仓时间匹配报告周期(由 StartTime 和 EndTime 变量定义) - 则此仓位被记录到报告中(所有的输入和输出)。
除交易表外,还有一个新的当前金融工具图表被打开。此图表的所有必要属性均已提供,并用 ChartScreenShot() 函数做了一个屏幕截图 - 这样我们就能获取带有当前工具价格图表的图像文件了。接下来,此图表上的价格图表会被隐藏,余额变动图表会被绘制,然后再创建另一个屏幕截图。
两个带有图表的图像文件和带有报告的 HTML 文件创建之后,通过 FTP 发送文件的功能即被勾选。如果允许 - 则会根据赫兹量化中指定的设置,利用 SendFTP() 函数发送 "report.html"、"picture1.gif" 和 "picture2.gif" 文件。
启动 MetaQuotes Language Editor (语言编辑器),开始创建一个脚本。定义常量 - 图表刷新超时(以秒计)、价格图表的宽度和高度以及平衡图表的最大宽度。显示余额变动曲线的图表周期,根据报告周期的期限和图表的最大宽度进行选择。图表的宽度调整为平衡图所需的尺寸。
图表的高度自动计算为宽度的一半。赫兹量化还要将纵轴的宽度指定为常量 - 即图形面积相比图像宽度因纵轴而缩减的像素数。
#define timeout 10 // 图表刷新时间
#define Picture1_width 800 // 报告中图表最大宽度
#define Picture2_width 800 // 报告中价格图表宽度
#define Picture2_height 600 // 报告中价格图表高度
#define Axis_Width 59 // 纵轴宽度 (以像素为单位)
指定将从用户请求的输入参数。
// 请求输入参数
#property script_show_inputs
创建报告周期的枚举。
// 报告周期的枚举
enum report_periods
{
All_periods,
Last_day,
Last_week,
Last_month,
Last_year
};
就报告周期询问用户(默认为整个周期)。
// 询问报告周期
input report_periods ReportPeriod=0;
编写 OnStart() 函数的主体。
void OnStart()
{
确定报告周期的开头和结尾。
datetime StartTime=0; // 报告周期起始时间
datetime EndTime=TimeCurrent(); // 报告周期结束时间
// 计算报告周期起始时间
switch(ReportPeriod)
{
case 1:
StartTime=EndTime-86400; // 日
break;
case 2:
StartTime=EndTime-604800; // 周
break;
case 3:
StartTime=EndTime-2592000; // 月
break;
case 4:
StartTime=EndTime-31536000; // 年
break;
}
// 如果不是以上的选项, 那么 StartTime=0 (整个周期)
声明将在本程序内使用的变量。变量的用途描述见评论。
int total_deals_number; // 历史数据中的交易总数
int file_handle; // 文件句柄
int i,j; // 循环计数器
int symb_total; // 交易中的资产数量
int symb_pointer; // 当前资产的指针
char deal_status[]; // 交易状态 (处理/未处理)
ulong ticket; // 交易订单号
long hChart; // 图表 id
double balance; // 当前余额值
double balance_prev; // 之前余额值
double lot_current; // 当前交易交易量
double lots_list[]; // 根据资产种类的开放交易量列表
double current_swap; // 当前交易的库存费
double current_profit; // 当前交易的利润
double max_val,min_val; // 最大值和最小值
string symb_list[]; // 交易的资产种类列表
string in_table_volume; // 建仓交易量
string in_table_time; // 进场时间
string in_table_price; // 进场价格
string out_table_volume; // 出场交易量
string out_table_time; // 出场时间
string out_table_price; // 出场价格
string out_table_swap; // 出场库存费
string out_table_profit; // 出场利润
bool symb_flag; // 资产在列表中的标志
datetime time_prev; // 前面的时间值
datetime time_curr; // 当前时间值
datetime position_StartTime; // 建仓时间
datetime position_EndTime; // 最后一个退场时间
ENUM_TIMEFRAMES Picture1_period; // 余额图表时段
打开一个新图表并设置其属性 - 这是一个价格图表,会在报告底部输出。
// 开启一个新图表并设置其属性
hChart=ChartOpen(Symbol(),0);
ChartSetInteger(hChart,CHART_MODE,CHART_BARS); // 柱状图
ChartSetInteger(hChart,CHART_AUTOSCROLL,true); // 启用自动滚动
ChartSetInteger(hChart,CHART_COLOR_BACKGROUND,White); // 背景色为白色
ChartSetInteger(hChart,CHART_COLOR_FOREGROUND,Black); // 线和标签为黑色
ChartSetInteger(hChart,CHART_SHOW_OHLC,false); // 不显示OHLC
ChartSetInteger(hChart,CHART_SHOW_BID_LINE,true); // 显示 BID 线
ChartSetInteger(hChart,CHART_SHOW_ASK_LINE,false); // 隐藏 ASK 线
ChartSetInteger(hChart,CHART_SHOW_LAST_LINE,false); // 隐藏 LAST 线
ChartSetInteger(hChart,CHART_SHOW_GRID,true); // 显示网格线
ChartSetInteger(hChart,CHART_SHOW_PERIOD_SEP,true); // 显示时段分隔符
ChartSetInteger(hChart,CHART_COLOR_GRID,LightGray); // 网格线为浅灰色
ChartSetInteger(hChart,CHART_COLOR_CHART_LINE,Black); // 图表线为黑色
ChartSetInteger(hChart,CHART_COLOR_CHART_UP,Black); // 向上的柱为黑色
ChartSetInteger(hChart,CHART_COLOR_CHART_DOWN,Black); // 向下的柱为黑色
ChartSetInteger(hChart,CHART_COLOR_BID,Gray); // BID 线为灰色
ChartSetInteger(hChart,CHART_COLOR_VOLUME,Green); // 交易量和订单水平为绿色
ChartSetInteger(hChart,CHART_COLOR_STOP_LEVEL,Red); // SL 和 TP 水平为红色
ChartSetString(hChart,CHART_COMMENT,ChartSymbol(hChart)); // 注释包含资产种类
图表截屏,并将其保存为 "picture2.gif"。
// 把图表保存为图像文件
ChartScreenShot(hChart,"picture2.gif",Picture2_width,Picture2_height);
请求现有账户整个时间段的交易历史。
// 请求整个时段的交易历史
HistorySelect(0,TimeCurrent());
打开 "report.html" 文件,并在其中写入带有报告的 HTML 页面(ANSI 编码)。
// 打开图表文件
file_handle=FileOpen("report.html",FILE_WRITE|FILE_ANSI);
编写 HTML 文档的开头部分:
- html 文档的开头 (<html>)
- 显示于您浏览器窗口顶部的标题 (<head><title>“EA 交易报告”</title></head>)
- 带有背景色的 html 文档主体部分的开头 (<body bgcolor='#EFEFEF'>)
- 居中对齐 (<center>)
- 交易与仓位表的标题 (<h2>交易报告</h2>)
- 交易与仓位表的开头,带有对齐、边框宽度、背景颜色、边框颜色、单元格间距及单元格填充 (<table align='center' border='1' bgcolor='#FFFFFF' bordercolor='#7F7FFF' cellspacing='0' cellpadding='0'>)
- 表标题
// 写 HTML 开头部分
FileWrite(file_handle,"<html>"+
"<head>"+
"<title>Expert Trade Report</title>"+
"</head>"+
"<body bgcolor='#EFEFEF'>"+
"<center>"+
"<h2>Trade Report</h2>"+
"<table align='center' border='1' bgcolor='#FFFFFF' bordercolor='#7F7FFF' cellspacing='0' cellpadding='0'>"+
"<tr>"+
"<th rowspan=2>SYMBOL</th>"+
"<th rowspan=2>Direction</th>"+
"<th colspan=3>Open</th>"+
"<th colspan=3>Close</th>"+
"<th rowspan=2>Swap</th>"+
"<th rowspan=2>Profit</th>"+
"</tr>"+
"<tr>"+
"<th>Volume</th>"+
"<th>Time</th>"+
"<th>Price</th>"+
"<th>Volume</th>"+
"<th>Time</th>"+
"<th>Price</th>"+
"</tr>");
获取列表中的交易数量。