- 显示:
- 84
- 等级:
- 已发布:
-
需要基于此代码的EA交易或指标吗?请在自由职业者服务中订购 进入自由职业者服务
EAToMath 库的替代品https://www.mql5.com/zh/code/61283
以真实刻度模式记录刻度,以数学模式读取刻度,每记录一个刻度就调用一个策略。
创建原因:MQ 测试程序,每次运行优化器时都会向每个代理写入刻度数据文件。我有 36 个代理,每个代理为一个工具和测试期写入 10GB 的数据,在 480GB 的硬盘上总共写入 360GB。每次优化前,这个过程大约需要 1 个小时。一般固态硬盘的使用寿命为 500-1000 次写入循环。如果每次重写 360GB,资源很快就会耗尽。该库只写入一个文件,然后所有 36 个代理都将从这一个文件中读取数据。所有这些都是我们编写该库的原因:我们只使用 1 个文件 + 为每个代理节省 1 个小时的数据写入时间 + 与 MQ 测试仪相比甚至与真实滴答模式下的虚拟测试仪相比都更快。
这个问题是与 fxsaber(EAToMath 的作者)同时研究的,每个人都有自己的版本。
交易操作使用 MT4Orders 库https://www.mql5.com/zh/code/16006
虚拟交易需要使用 Virtual 库https://www.mql5.com/zh/code/22577
查看交易结果可以使用 MT4Orders QuickReporthttps://www.mql5.com/zh/code/47816 或 Report
压缩刻度线 TickCompressorhttps://www.mql5.com/zh/code/66201
删除可能不必要的刻度线 Control_Trade_Sessions 库https://www.mql5.com/zh/code/48059 连接,例如,如果报价时段大于交易时段。如果使用了所有刻度线,即交易时段重合,也可以将其删除。
与 EAToMath 的区别:
优点
- 代码更短更简单,只有 5 个插件库。如果需要修改,会更容易理解。
- 由于采用了不同的算法,数据压缩效果更好https://www.mql5.com/zh/code/66201。 当仅保存 time_msc、ask 和 bid 时,多达 86% 的 ticks 被保存为 3 字符数字,即 3 字节。当保存 2023 年的 BTCUSDT 时间点数据时,每个时间点的平均大小 = 3.266 字节。
,当保存交易量时,平均大小 = 4.835 字节。保存完整刻度 = 8.439 字节。下表是测试结果。
此外,您还可以使用内置的 ZIP 归档功能。文件大小会缩小 2 倍。这样一个文件的大小为 245 Mb,而 2023 年的 .tcs 文件大小总和为 364 Mb,即压缩率是 MQ 的 1.5 倍。而数学模式下的刻度生成速度要快 2 倍。见下表。 - 保存方式有更多选择:

- 通过在系统中建立链接,可以将文件保存到 SSD 或 RAM 磁盘中。文件会占用大量空间,RAM 盘可能不够用,因此可以选择保存到主硬盘。固态硬盘和内存的读取速度差不多,我听说固态硬盘可以缓存最常请求的数据的全部容量的 5%。
固态硬盘在读取数据时会有一些损耗,因为与不读取数据的存储方式相比,你需要更频繁地覆盖内存单元。我不知道确切的数字,但举例来说,每 10 次读取或每 1000 次读取就会覆盖 1 次....。但与 MQ 测试仪对磁盘的磨损相比,这并不重要。
缺点
- 连接 Virtual 必须自己完成(使用说明见https://www.mql5.com/zh/code/22577),EAToMath 会将您的策略传递给 Virtual 本身。
BidAsk 变体的速度与 EAToMath 相当。其他变体速度较慢,因为它们要么包含更多数据,要么有额外的 ZIP 压缩。
使用特点:
不能在策略中使用标准函数Symbol()、Digits() (=4)、Point() (=0.0001),因为它们会产生默认值,与测试中的符号无关。取而代之的是使用_Symbol、_Digits、_Point ,它们会根据从文件中读取的值进行重载。此外,还添加了带有记录符号值的新常数_TickSize 和_TickValue - 它们是正确计算利润、佣金和存款货币掉期所必需的。
保存刻度时选择测试期的工作顺序:
- 通过实际点数、所需工具和测试日期选择测试模式。将任务变量设置为 "保存",并选择 "保存刻度 "选项。启动测试仪。之后将在指定文件夹中创建包含刻度的文件。
- 将任务变量设置为 Run_Strategy。您可以稍后通过真实刻度来离开模式进行比较。启动测试仪。计算采用真实刻度,而不是文件中的刻度。获取结果。

- 将测试模式设置为数学计算。启动测试仪。通过文件中的刻度进行计算。与步骤 2 的结果进行比较,结果应该相同,但速度要快几倍。
存档的工作顺序
- 创建包含历史记录中所有刻度点的存档: 选择实际刻度点测试模式和所需仪器。在可用历史记录中设置从 <= 第一个刻度点到 >= 最后一个刻度点的测试日期。将任务变量设置为 "保存...到存档",并选择 "保存刻度 "选项。启动测试仪。然后将在指定文件夹中创建一个带有工具名称的文件夹,并在其中保存每年的刻度文件。必要时可以覆盖最后一年的数据,为此在日期中只选择当年,以避免覆盖前几年的数据。
- 将测试模式设置为数学。将任务变量设置为 Run_Strategy_Fron_Archive。
- 在 " MathTicker:使用完整存档 组 "中设置:
Instrument - 为仪器名称(必须与存储其刻度的文件夹名称一致)、测试的开始和结束日期。

- 启动测试仪。通过所需年度文件中的刻度进行计算。由于不是通过一个文件,而是通过多个文件进行计算,因此计算速度会稍慢一些,因为打开和关闭文件都需要时间。例如,生成 3 年的刻度值需要 2.7 秒,而不是 1.7 秒。
- 以下智能交易系统获得的刻度线总和可能与第一个刻度线的数值相差很小。在真实刻度线模式下对自定义字符进行测试时,第一个刻度线只产生 Ask 或 Bid(如果您没有同时保存这两个刻度线)。从存档进行测试时,它们都会从以前的刻度中恢复。
以最简单的智能交易系统为例,估算工作速度:
#property tester_no_cache #include <Forester\MathTicker.mqh> // 在数学模式下连接交易 input int rep=0;//重复优化 sinput bool AddVolumes=true; void OnInit(){} void OnTick(){ static MqlTick Tick; if (SymbolInfoTick(_Symbol, Tick)){ #ifdef _MathTick_ if(MathTick.SaveTick(Tick)){ return; }//if we save ticks, then exit and do not trade. #endif Strategy(Tick); } } double Sum = 0;int tk=0; void Strategy(MqlTick& Tick){ // 最简单的策略 - 用于比较 EAToMath 的阅读速度 Sum += Tick.bid+Tick.ask+(AddVolumes?Tick.volume_real:0.0); tk++; //if(tk<100){Print(Tick.time," " ",Tick.ask," ",Tick.bid," ",Tick.last," ",Tick.volume_real," ",Tick.flags);} } ulong StartTime = GetMicrosecondCount(); double OnTester(){ #ifdef _MathTick_ // 使用 MathTick 运行 - 它会以刻度计数文件中的符号参数。对于 mat 模式下的测试 if(MathTick.SaveTicksEnd()){return 0;}// 记录刻度后关闭文件并退出 if(MathTick.ReadSymbolVars()){ MathTick.Ticker();// 在 mat 模式下,将向 Strategy(MqlTick &Tick) 发送所有刻度线。 } #endif Print("ticks: ",tk); long work_time = (long)(GetMicrosecondCount() - StartTime)/1000; //return(NormalizeDouble(work_time, 1)); // 得到工作速度和工作时间。 return Sum;// 比较计算结果 }
您可以切换 1 项设置:
//#define RestoreFlags // восстановить флаги тика из изменения ask, bid, volume - добавит 7% к времени генерации тиков 931 вместо 869 мс
下面是统计数据、交易量和交易时间的打印输出。
-----------
无卷 MQ测试仪
pass 1 返回结果 4345830621850.311523 in0:00:08.232
| C ZIP 压缩 | |
|---|---|
| AskBid.文件大小:225 mb -------------------- 统计数据:-------------------- 3 bytes: 86.6%, 62644158 ticks 4 bytes: 0.6%, 412167 ticks 5 bytes: 12.7%, 9185484 ticks 6 bytes: 0.0%, 15274 ticks 11 bytes: 0.1%, 46214 ticks 12 bytes: 0.0%, 1 ticks 24 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 236108596 bytes. Average: 3.266 bytes per tick final balance 0.00 USD pass 10 returned result 4345830621850.311523 in 0:00:01.485 no normalisation pass 1 returned result 4345830621850.311523 in0:00:00.892 | AskBid_Zipped.文件大小:106 mb -------------------- 统计数据: -------------------- 3 个字节:86.6%,62644158 ticks 4 个字节:0.6%,412167 ticks 5 个字节:12.7%,9185484 ticks 6 个字节:0.0%, 15274 ticks 11 bytes: 0.1%, 46214 ticks 12 bytes: 0.0%, 1 ticks 24 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 236108596 bytes. Average: 3.266 bytes per tick UnZipped size:236108596.已压缩大小:111720863。ZIP 压缩率:47.3% pass 10 返回结果 4345830621850.311523,时间为 0:00:02.548 无规范化 pass 2 返回结果 4345830621850.311523,时间为0:00:01.890 |
带有卷的 MQ 测试仪
通过 1 返回结果 4345879117123.356445,时间为0:00:07.962
| C ZIP 压缩 | |
|---|---|
| AskBidVolume.文件大小:333 mb -------------------- 统计数据:-------------------- 4 个字节:60.4%,43684907 ticks 5 个字节:1.1%,809676 ticks 6 个字节:33.5%, 24194111 ticks 7 bytes: 4.9%, 3548666 ticks 8 bytes: 0.0%, 7909 ticks 12 bytes: 0.1%, 40022 ticks 13 bytes: 0.0%, 17964 ticks 14 bytes: 0.0%, 2 ticks 19 bytes: 0.0%, 41 ticks 32 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 349571243 bytes. Average: 4.835 bytes per tick pass 1 returned result 4345879117123.356445 in 0:00:02.803 no normalisation pass 4 returned result 4345879117123.356445 in0:00:01.659 | AskBidVolume_Zipped.文件大小 : 204 mb -------------------- 统计数据:-------------------- 4 个字节:60.4%,43684907 ticks 5 个字节:1.1%,809676 ticks 6 个字节:33.5%,24194111 ticks 7 个字节:4.9%,3548666 ticks 8 个字节:0.0%, 7909 ticks 12 bytes: 0.1%, 40022 ticks 13 bytes: 0.0%, 17964 ticks 14 bytes: 0.0%, 2 ticks 19 bytes: 0.0%, 41 ticks 32 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 349571243 bytes. Average: 4.835 bytes per tick UnZipped size:349571243.已压缩大小:214897079。ZIP 压缩:61.5% pass 2 返回结果 4345879117123.356445,时间为 0:00:04.260 无规范化 pass 2 返回结果 4345879117123.356445,时间为 0:00:03.096 |
| 全部。文件大小: 582 mb -------------------- 统计数据:-------------------- 8 个字节:61.5%,44494583 个刻度线 9 个字节:33.5%,24194111 个刻度线 10 个字节:4.9%,3548666 个刻度线 11 个字节:0.0%,7909 个刻度线 15 个字节:0.1%,40022 个刻度线 16 个字节:0.0%,17964 个刻度线 17 个字节:0.0%, 2 ticks 22 bytes: 0.0%, 41 ticks 44 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 610166056 bytes. Average: 8.439 bytes per tick pass 2 returned result 4345879117123.356445 in 0:00:03.768 no normalisation pass 1 returned result 4345879117123.356445 in0:00:02.256 | All_Zipped.文件大小:245 mb -------------------- 统计数据: -------------------- 8 个字节:61.5%,44494583 ticks 9 个字节:33.5%,24194111 ticks 10 个字节:4.9%,3548666 ticks 11 个字节:0.0%,7909 ticks 15 个字节:0.1%, 40022 ticks 16 bytes: 0.0%, 17964 ticks 17 bytes: 0.0%, 2 ticks 22 bytes: 0.0%, 41 ticks 44 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 610166056 bytes. Average: 8.439 bytes per tick UnZipped size:610166056.已压缩大小:257105213。ZIP 压缩:42.1 % pass 1 返回结果 4345879117123.356445 in 0:00:05.388 无正常化 pass 10 返回结果 4345879117123.356445 in0:00:03.936 |
2023 年同一年份的 .tcs 文件大小:

所有使用 ZIP 的变体,即使是全刻度线保存也更加紧凑(3.5 到 1.5 倍)。
虚拟交易和报告输出的智能交易系统示例:
#property tester_no_cache #include <MT4Orders.mqh> // https://www.mql5.com/zh/code/16006 #include <Forester\MathTicker.mqh> // 在数学模式下连接交易 #define ORDER_CURRENCY_DIGITS 2 // 在交易历史中计算利润/佣金/隔夜利息的位数设置。 #define VIRTUAL_LIMITS_TP_SLIPPAGE // 限价和止损以第一个接受价格执行 - 正滑点 #define ORDER_COMMISSION -0 // 佣金分配 = Lots * ORDER_COMMISSION。 #include <fxsaber\Virtual\Virtual.mqh> // https://www.mql5.com/zh/code/22577 #define REPORT_TESTER // 测试仪将自动记录报告 #define REPORT_BROWSER // 在浏览器启动时创建报告 - 需要 DLL 许可。 #define USE_highcharts //- 您可以免费下载和试用所有 Highcharts 产品。一旦您的项目/产品准备就绪,即可购买商业许可证。https://shop.highcharts.com/。 #include <MT4Orders_QuickReport.mqh>// enum VirtTyp {MQ_Tester=0,Virtual1=1,Virtual2=2}; sinput VirtTyp tester1=1;//测试仪 1 sinput VirtTyp tester2=2;//测试仪 2 input int rep=0;//重复优化 bool isOptimization = false, isTester=false; double balInit=0; VIRTUAL_POINTER Virtual[10]; void OnInit(){ Virtual[0] = 0; // 0 - 真实交易环境 Virtual[1] = VIRTUAL::Create(AccountBalance()); // 创建虚拟化 1. Virtual[2] = VIRTUAL::Create(AccountBalance()); // 创建虚拟化 2. //Virtual[tester1].Select(); isOptimization = MQLInfoInteger(MQL_OPTIMIZATION) ; isTester = MQLInfoInteger(MQL_TESTER); balInit=AccountBalance(); } void OnTick(){ //Virtual[0].Select(); VIRTUAL::NewTick();// 将勾选发送到当前虚拟机 static MqlTick Tick; if (SymbolInfoTick(_Symbol, Tick)){ #ifdef _MathTick_ if(MathTick.SaveTick(Tick)){ return; }//当写入 ticks 时将退出函数,Strategy() 将不会被调用 #endif Strategy(Tick);//交易 } } void Strategy(MqlTick& Tick){ // 最简单的策略 - 用于比较 EAToMath 的阅读速度 if(Tick.ask==0 || Tick.bid==0){return;}/MQ测试器在交易失败时进行交易,而Virtual不进行交易。也禁止 MQ if(tester1>0){Virtual[tester1].Select(); VIRTUAL::NewTick(Tick);}//选择虚拟化 1 并打勾 if(tester2>0){Virtual[tester2].Select(); VIRTUAL::NewTick(Tick);}//选择虚拟化 2 并打勾 if(isNewHour(Tick.time)){//每小时的第一个刻度 if(GetHour0(Tick.time) % 2==0){// 在测试仪 1 的偶数小时购买 Virtual[tester1].Select();//选择虚拟化 1 OrderSend(_Symbol, OP_BUY, 1, Tick.ask, 0, Tick.ask - 100 * _Point, Tick.ask + 100 * _Point); }else{//在测试仪 2 中零时销售 Virtual[tester2].Select();//选择虚拟化 2 OrderSend(_Symbol, OP_SELL, 1, Tick.bid, 0, Tick.bid + 100 * _Point, Tick.bid - 100 * _Point); } } } double OnTester(){ #ifdef _MathTick_ // 使用 MathTick 运行 - 它会从 tick 文件读取符号参数。对于 mat 模式下的测试 if(MathTick.SaveTicksEnd()){return 0;}//滴答保存后返回 if(MathTick.isMath && MathTick.ReadSymbolVars()){ if(tester1==0){Alert(" >>>>>>>>> Virtual tester 1=MQ. In math mode can be used only virtual tester. <<<<<<<<");return 0;} if(tester2==0){Alert(" >>>>>>>>> Virtual tester 1=MQ. In math mode can be used only virtual tester. <<<<<<<<");return 0;} SYMBOL_BASE sb; sb.Point=_Point; sb.Digits=_Digits; sb.Symbol=_Symbol; sb.SymbolID=0; sb.TickSize=_TickSize; sb.TickValue=_TickValue / _TickSize;//this.TickValue_ /= this.TickSize_; //as in SetSymbol() in \fxsaber\Virtual\Symbol_Base.mqh Virtual[1].Select(); VIRTUAL::SetSymbolBase(sb); Virtual[2].Select(); VIRTUAL::SetSymbolBase(sb); //minFreezeLevel = _minFreezeLevel*_Point; minStopLevel = _minStopLevel*_Point; Virtual[tester1].Select(); MathTick.Ticker();// 在 mat 模式下,将向 Strategy(MqlTick &Tick) 发送所有刻度线。 } #endif double ret_val=0; for (int v = 0 ; v <= VIRTUAL::Total(); v++){ if(Virtual[v].Select()){ if(v > 0){ VIRTUAL::Stop(); #ifdef _MathTick_ // 使用 MathTick 运行 - 它会从 tick 文件读取符号参数。对于 mat 模式下的测试 if(MathTick.isMath){ VIRTUAL::CalcSwaps( MathTick.swapShort, MathTick.swapLong, 0, MathTick.swap3days ); }//从勾选文件中调换 else{VIRTUAL::CalcSwaps( _Symbol, 0 );} #else VIRTUAL::CalcSwaps( _Symbol, 0 );//计算掉期 - 所有交易都有一个掉期,即如果有 2 个以上不同的工具,它们都将有主符号的掉期。 #endif }// 以最后一个刻度线的价格关闭未完成的交易,与测试版一样 if( !isOptimization){QuickReport("report_"+(string)v, true, v,false,true);} Print((string)v+" AccountBalance = ",AccountBalance(), " AccountEquity = ",AccountEquity()); double prib=AccountBalance()-balInit; ret_val += prib; // }} return ret_val;// 比较计算结果 } bool isNewHour (datetime &t){ static int next_h=-1; if(t < next_h){ return false; } else { next_h = (GetHour0(t)+1)*3600;return true;}} int GetHour0 (datetime &t){return((int)( t / 3600));}//1971年1月1日起的当前时间
该示例创建了 2 个不同交易的虚拟机。在偶数小时,一个测试者买入,另一个在奇数小时卖出。
这是一个有 2 个测试器的复杂示例,如果只需要一个测试器,则可以简化。
您还可以选择 MQ 测试器,将其与虚拟测试器的结果进行比较,以控制计算的正确性。只有佣金可能不一致,因为有许多不同的佣金,而虚拟测试器中只编程了一个变量。
。
由MetaQuotes Ltd译自俄语
原代码: https://www.mql5.com/ru/code/65821
根据每笔存款的风险计算手数的功能
该函数计算未结头寸的手数。交易的开仓价、止损价和每笔交易的风险(以保证金的百分比为单位)作为参数传入
ATR Cycles
基于 3 个 ATR 的波动率过滤器:快速 ATR、中间 ATR 和慢速 ATR
SAR ADX Signal
带移动通知的 SAR ADX 信号,由 MT4 版本改写而成(已找不到源代码)。 这是一个可重新绘制的指标,使用时请小心。
随机动量彩色蜡烛图
安德烈-F-泽林斯基根据威廉-布劳的指标提出的构想