//+------------------------------------------------------------------+
//| CustomTicksAdd.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"
#define CUSTOM_SYMBOL_NAME Symbol()+".C" // 自定义交易品种名称
#define CUSTOM_SYMBOL_PATH "Forex" // 创建的交易品种所在组的名称
#define CUSTOM_SYMBOL_ORIGIN Symbol() // 自定义交易品种的基础交易品种名称
#define DATATICKS_TO_COPY UINT_MAX // 复制的报价数量
#define DATATICKS_TO_PRINT 20 // 发送到日志中的报价数量
//+------------------------------------------------------------------+
//| 脚本程序起始函数 ||
//+------------------------------------------------------------------+
void OnStart()
{
//--- 取得创建自定义交易品种时的错误代码
int create=CreateCustomSymbol(CUSTOM_SYMBOL_NAME, CUSTOM_SYMBOL_PATH, CUSTOM_SYMBOL_ORIGIN);
//--- 如果错误代码不为0 (创建交易品种成功) 也不为 5304 (交易品种已经被创建) - 退出
if(create!=0 && create!=5304)
return;
//--- 把标准交易品种的报价数据读取至 MqlTick 数组中
MqlTick array[]={};
if(!GetTicksToArray(CUSTOM_SYMBOL_ORIGIN, DATATICKS_TO_COPY, array))
return;
//--- 打印接收到的标准交易品种的第一个和最后一个报价的时间
int total=(int)array.Size();
PrintFormat("First tick time: %s.%03u, Last tick time: %s.%03u",
TimeToString(array[0].time, TIME_DATE|TIME_MINUTES|TIME_SECONDS), array[0].time_msc%1000,
TimeToString(array[total-1].time, TIME_DATE|TIME_MINUTES|TIME_SECONDS), array[total-1].time_msc%1000);
//--- 把标准交易品种最后一个报价的 DATATICKS_TO_PRINT 数据打印至日志中
PrintFormat("\nThe last %d ticks for the standard symbol '%s':", DATATICKS_TO_PRINT, CUSTOM_SYMBOL_ORIGIN);
for(int i=total-DATATICKS_TO_PRINT; i<total; i++)
{
if(i<0)
continue;
PrintFormat(" %dth Tick: %s", i, GetTickDescription(array[i]));
}
//--- 在市场报价窗口中添加一个自定义交易品种
ResetLastError();
if(!SymbolSelect(CUSTOM_SYMBOL_NAME, true))
{
Print("SymbolSelect() failed. Error ", GetLastError());
return;
}
//--- 把报价数组数据添加到自定义交易品种的价格历史中
Print("...");
uint start=GetTickCount();
PrintFormat("Start of adding %u ticks to the history of the custom symbol '%s'", array.Size(), CUSTOM_SYMBOL_NAME);
int added=CustomTicksAdd(CUSTOM_SYMBOL_NAME, array);
PrintFormat("Added %u ticks to the history of the custom symbol '%s' in %u ms", added, CUSTOM_SYMBOL_NAME, GetTickCount()-start);
//--- 把自定义交易品种报价数据读取至 MqlTick 数组中
Print("...");
if(!GetTicksToArray(CUSTOM_SYMBOL_NAME, array.Size(), array))
return;
//--- 打印收到的自定义交易品种第一个和最后一个报价的时间
total=(int)array.Size();
PrintFormat("First tick time: %s.%03u, Last tick time: %s.%03u",
TimeToString(array[0].time, TIME_DATE|TIME_MINUTES|TIME_SECONDS), array[0].time_msc%1000,
TimeToString(array[total-1].time, TIME_DATE|TIME_MINUTES|TIME_SECONDS), array[total-1].time_msc%1000);
//--- 把自定义交易品种最后报价的 DATATICKS_TO_PRINT 数据打印到日志中
PrintFormat("\nThe last %d ticks for the custom symbol '%s':", DATATICKS_TO_PRINT, CUSTOM_SYMBOL_NAME);
for(int i=total-DATATICKS_TO_PRINT; i<total; i++)
{
if(i<0)
continue;
PrintFormat(" %dth Tick: %s", i, GetTickDescription(array[i]));
}
//--- 在图表注释区显示脚本终止键的提示
Comment(StringFormat("Press 'Esc' to exit or 'Del' to delete the '%s' symbol and exit", CUSTOM_SYMBOL_NAME));
//--- 在无尽循环中等待按下 Esc 或 Del 键
while(!IsStopped() && TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)==0)
{
Sleep(16);
//--- 当按下 Del 时, 删除所创建的自定义交易品种和它的数据
if(TerminalInfoInteger(TERMINAL_KEYSTATE_DELETE)<0)
{
//--- 删除柱形数据
int deleted=CustomRatesDelete(CUSTOM_SYMBOL_NAME, 0, LONG_MAX);
if(deleted>0)
PrintFormat("%d history bars of the custom symbol '%s' were successfully deleted", deleted, CUSTOM_SYMBOL_NAME);
//--- 删除报价数据
deleted=CustomTicksDelete(CUSTOM_SYMBOL_NAME, 0, LONG_MAX);
if(deleted>0)
//--- 删除交易品种
if(DeleteCustomSymbol(CUSTOM_SYMBOL_NAME))
PrintFormat("Custom symbol '%s' deleted successfully", CUSTOM_SYMBOL_NAME);
break;
}
}
//--- 退出前清空图表
Comment("");
/*
结果:
Requested 4294967295 ticks to download tick history for the symbol 'EURUSD'
The tick history for the 'EURUSD' symbol is received in the amount of 351183943 ticks in 56454 ms
First tick time: 2011.12.19 00:00:08.000, Last tick time: 2024.06.20 21:18:12.010
The last 20 ticks for the standard symbol 'EURUSD':
351183923th Tick: 2024.06.20 21:17:46.380 Bid=1.07124 (Info tick)
351183924th Tick: 2024.06.20 21:17:47.779 Ask=1.07125 Bid=1.07125 (Info tick)
351183925th Tick: 2024.06.20 21:17:48.584 Ask=1.07124 Bid=1.07124 (Info tick)
351183926th Tick: 2024.06.20 21:17:49.481 Ask=1.07125 (Info tick)
351183927th Tick: 2024.06.20 21:17:49.985 Ask=1.07122 Bid=1.07122 (Info tick)
351183928th Tick: 2024.06.20 21:17:50.482 Ask=1.07124 Bid=1.07124 (Info tick)
351183929th Tick: 2024.06.20 21:17:51.584 Ask=1.07123 Bid=1.07123 (Info tick)
351183930th Tick: 2024.06.20 21:17:52.786 Ask=1.07124 Bid=1.07124 (Info tick)
351183931th Tick: 2024.06.20 21:17:53.487 Ask=1.07125 Bid=1.07125 (Info tick)
351183932th Tick: 2024.06.20 21:17:53.989 Ask=1.07126 Bid=1.07126 (Info tick)
351183933th Tick: 2024.06.20 21:17:55.789 Ask=1.07125 Bid=1.07125 (Info tick)
351183934th Tick: 2024.06.20 21:17:58.495 Ask=1.07126 Bid=1.07126 (Info tick)
351183935th Tick: 2024.06.20 21:18:00.102 Bid=1.07126 (Info tick)
351183936th Tick: 2024.06.20 21:18:00.698 Ask=1.07129 Bid=1.07129 (Info tick)
351183937th Tick: 2024.06.20 21:18:03.699 Bid=1.07129 (Info tick)
351183938th Tick: 2024.06.20 21:18:04.699 Ask=1.07128 Bid=1.07128 (Info tick)
351183939th Tick: 2024.06.20 21:18:05.901 Ask=1.07129 Bid=1.07129 (Info tick)
351183940th Tick: 2024.06.20 21:18:07.606 Ask=1.07128 Bid=1.07128 (Info tick)
351183941th Tick: 2024.06.20 21:18:11.512 Ask=1.07127 Bid=1.07127 (Info tick)
351183942th Tick: 2024.06.20 21:18:12.010 Ask=1.07126 Bid=1.07126 (Info tick)
...
Start of adding 351183943 ticks to the history of the custom symbol 'EURUSD.C'
Added 351183943 ticks to the history of the custom symbol 'EURUSD.C' in 269890 ms
...
Requested 351183943 ticks to download tick history for the symbol 'EURUSD.C'
The tick history for the 'EURUSD.C' symbol is received in the amount of 351183943 ticks in 116407 ms
First tick time: 2011.12.19 00:00:08.000, Last tick time: 2024.06.20 21:18:12.010
The last 20 ticks for the custom symbol 'EURUSD.C':
351183923th Tick: 2024.06.20 21:17:46.380 Ask=1.07124 Bid=1.07124 (Info tick)
351183924th Tick: 2024.06.20 21:17:47.779 Ask=1.07125 Bid=1.07125 (Info tick)
351183925th Tick: 2024.06.20 21:17:48.584 Ask=1.07124 Bid=1.07124 (Info tick)
351183926th Tick: 2024.06.20 21:17:49.481 Ask=1.07125 Bid=1.07125 (Info tick)
351183927th Tick: 2024.06.20 21:17:49.985 Ask=1.07122 Bid=1.07122 (Info tick)
351183928th Tick: 2024.06.20 21:17:50.482 Ask=1.07124 Bid=1.07124 (Info tick)
351183929th Tick: 2024.06.20 21:17:51.584 Ask=1.07123 Bid=1.07123 (Info tick)
351183930th Tick: 2024.06.20 21:17:52.786 Ask=1.07124 Bid=1.07124 (Info tick)
351183931th Tick: 2024.06.20 21:17:53.487 Ask=1.07125 Bid=1.07125 (Info tick)
351183932th Tick: 2024.06.20 21:17:53.989 Ask=1.07126 Bid=1.07126 (Info tick)
351183933th Tick: 2024.06.20 21:17:55.789 Ask=1.07125 Bid=1.07125 (Info tick)
351183934th Tick: 2024.06.20 21:17:58.495 Ask=1.07126 Bid=1.07126 (Info tick)
351183935th Tick: 2024.06.20 21:18:00.102 Ask=1.07126 Bid=1.07126 (Info tick)
351183936th Tick: 2024.06.20 21:18:00.698 Ask=1.07129 Bid=1.07129 (Info tick)
351183937th Tick: 2024.06.20 21:18:03.699 Ask=1.07129 Bid=1.07129 (Info tick)
351183938th Tick: 2024.06.20 21:18:04.699 Ask=1.07128 Bid=1.07128 (Info tick)
351183939th Tick: 2024.06.20 21:18:05.901 Ask=1.07129 Bid=1.07129 (Info tick)
351183940th Tick: 2024.06.20 21:18:07.606 Ask=1.07128 Bid=1.07128 (Info tick)
351183941th Tick: 2024.06.20 21:18:11.512 Ask=1.07127 Bid=1.07127 (Info tick)
351183942th Tick: 2024.06.20 21:18:12.010 Ask=1.07126 Bid=1.07126 (Info tick)
*/
}
//+------------------------------------------------------------------+
//| 创建一个自定义交易品种, 返回错误代码 |
//+------------------------------------------------------------------+
int CreateCustomSymbol(const string symbol_name, const string symbol_path, const string symbol_origin=NULL)
{
//--- 定义自定义交易品种所基于的交易品种名称
string origin=(symbol_origin==NULL ? Symbol() : symbol_origin);
//--- 如果创建自定义交易品种失败并且错误代码不是 5304, 在日志中报告
ResetLastError();
int error=0;
if(!CustomSymbolCreate(symbol_name, symbol_path, origin))
{
error=GetLastError();
if(error!=5304)
PrintFormat("CustomSymbolCreate(%s, %s, %s) failed. Error %d", symbol_name, symbol_path, origin, error);
}
//--- 成功
return(error);
}
//+------------------------------------------------------------------+
//| 删除一个自定义交易品种 |
//+------------------------------------------------------------------+
bool DeleteCustomSymbol(const string symbol_name)
{
//--- 从市场报价窗口中隐藏交易品种
ResetLastError();
if(!SymbolSelect(symbol_name, false))
{
PrintFormat("SymbolSelect(%s, false) failed. Error %d", GetLastError());
return(false);
}
//--- 如果删除自定义交易品种失败,在日志中报告并返回 'false'
ResetLastError();
if(!CustomSymbolDelete(symbol_name))
{
PrintFormat("CustomSymbolDelete(%s) failed. Error %d", symbol_name, GetLastError());
return(false);
}
//--- 成功
return(true);
}
//+------------------------------------------------------------------+
//| 把指定数量的报价读取到数组中 |
//+------------------------------------------------------------------+
bool GetTicksToArray(const string symbol, const uint count, MqlTick &array[])
{
//--- 通知开始载入历史数据
PrintFormat("Requested %u ticks to get tick history for the symbol '%s'", count, symbol);
//--- 为接收报价做3次尝试
int attempts=0;
while(attempts<3)
{
//--- 测量接收报价的开始时间
uint start=GetTickCount();
//--- 从 1970.01.01 00:00.001 (参数 from=1 ms) 开始请求报价历史
int received=CopyTicks(symbol, array, COPY_TICKS_ALL, 1, count);
if(received!=-1)
{
//--- 显示报价数量和花费的时间
PrintFormat("The tick history for the '%s' symbol is received in the amount of %u ticks in %d ms", symbol, received, GetTickCount()-start);
//--- 如果报价历史已同步, 错误代码等于0 - 返回 'true'
if(GetLastError()==0)
return(true);
PrintFormat("%s: Ticks are not synchronized yet, %d ticks received for %d ms. Error=%d",
symbol, received, GetTickCount()-start, GetLastError());
}
//--- 计数尝试次数
attempts++;
//--- 暂停一秒以等待报价数据库同步结束
Sleep(1000);
}
//--- 3次尝试复制报价失败
return(false);
}
//+------------------------------------------------------------------+
//| 返回报价的字符串类型描述 |
//+------------------------------------------------------------------+
string GetTickDescription(MqlTick &tick)
{
string desc=StringFormat("%s.%03u ", TimeToString(tick.time, TIME_DATE|TIME_MINUTES|TIME_SECONDS),tick.time_msc%1000);
//--- 检查报价标志
bool buy_tick = ((tick.flags &TICK_FLAG_BUY) == TICK_FLAG_BUY);
bool sell_tick = ((tick.flags &TICK_FLAG_SELL) == TICK_FLAG_SELL);
bool ask_tick = ((tick.flags &TICK_FLAG_ASK) == TICK_FLAG_ASK);
bool bid_tick = ((tick.flags &TICK_FLAG_BID) == TICK_FLAG_BID);
bool last_tick = ((tick.flags &TICK_FLAG_LAST) == TICK_FLAG_LAST);
bool volume_tick= ((tick.flags &TICK_FLAG_VOLUME)== TICK_FLAG_VOLUME);
//--- 首先检查用于交易的报价标志 (没有 CustomTicksAdd())
if(buy_tick || sell_tick)
{
//--- 构建交易报价的输出内容
desc += (buy_tick ? StringFormat("Buy Tick: Last=%G Volume=%d ", tick.last, tick.volume) : "");
desc += (sell_tick? StringFormat("Sell Tick: Last=%G Volume=%d ",tick.last, tick.volume) : "");
desc += (ask_tick ? StringFormat("Ask=%G ", tick.ask) : "");
desc += (bid_tick ? StringFormat("Bid=%G ", tick.ask) : "");
desc += "(Trade tick)";
}
else
{
//--- 构建信息报价的输出稍有不同
desc += (ask_tick ? StringFormat("Ask=%G ", tick.ask) : "");
desc += (bid_tick ? StringFormat("Bid=%G ", tick.ask) : "");
desc += (last_tick ? StringFormat("Last=%G ", tick.last) : "");
desc += (volume_tick? StringFormat("Volume=%d ",tick.volume): "");
desc += "(Info tick)";
}
//--- 返回报价描述
return(desc);
}
|