概论当开发并使用不同的交易工具时, 赫兹期货量化有时会遇到一些情况, 通过 extern 和 input 修饰符创建输入的标准方法难以满足需求。虽然我们有一个通用的解决方案, 以满足我们的所有需求, 但它有时相当繁琐和不灵活。让我们考虑以下情况作为例子。
使用标准工具来创建很少改变或根本不会改变的参数 (即, 订单魔幻数字或滑点值)。
如果在指标或 EA 的属性里, 从诸如 RSI, WPR 等十几款指标里选择唯一的一款指标作为数据源, 那么其中每款指标的所需参数均应在属性窗口里创建并可用, 尽管事实上我们仅需其中一套参数。这种类型的另一个例子是每周的 EA 操作日程。在周三时没必要保存周一和周二 (或周五) 相关的日期。但我们不得不这样做, 因为整个日程表位于输入部分。换言之, 在参数里描述动态创建的对象十分困难, 且是效率低下的任务。
如果我们需要在工具的属性列表中放置一张便条, 注释或题头, 赫兹期货量化要创建一个带有相应内容的新字符串属性。在某些时候这很不方便。
编辑切换为居中添加图片注释,不超过 140 字(可选)如何在文本文件中存储参数纯文本文件可作为附加的便利方法来创建并保存输入参数。您可以把您想要的任何东西放入其中, 除非它们可以很容易地编辑和移动。它们的结构可以如同 INI 文件那样安排。例如, 在文本文件里如何保存整数类数组如下所示:/*array size*/{array_size},5/*array*/{array_init},0,1,2,3,4在上述例子里, "锚点" 或 "分区名" 被写在字符串的起始, 紧跟的分区内容以逗号分隔。任何字符组成的字符串可以作为一个 "锚点"。这些文件被生成并保存在终端的 "沙箱" 里。下一步, 我们在指标、EA 或脚本的初始化模块里按照只读模式打开这个文件 (作为 CSV 文件)。当读取保存的数组时, 赫兹期货量化使用已知的名字 {array_size} 在文件里搜索 "锚点"。我们应当通过调用 FileSeek(handle,0,SEEK_SET) 移动文件指针到文件开始。现在, 让我们使用下一个已知名 {array_init} 来搜索下一个 "锚点"。当有所发现时, 我们简单地读取字符串, 这是根据数组类型进行转换的必要次数 (在此情况下, 执行整数转换)。ConfigFiles.mqh 包含文件包括一些简单函数, 实现了 "锚点" 搜索和数据搜索。换言之, 我们在所需的 CSV 格式文件里保存的对象一般应按照 "锚点" 紧跟逗号分隔的数据来描述。若有必要, 您可以使用尽可能多地 "锚点" 和随后数据, 但请记住, 一个 "锚点" 仅对应一个字符串。注释以及便条和指导可以按照各种格式写到文件的任何位置。不过, 这里有一个明显的需求: 文本不得破坏 "锚点" – 数据序列。其它期望条件 – 任何大的文本应位于文件末尾以便简洁地搜索 "锚点"。您可以在下边看到上述 EA 操作日程保存时的可能排布:….......{d0},0,0,22{d1},0,0,22{d2},1,0,22…........{d6},0,0,22
此处, "锚点" 名反映周内日期数, 使用确定的数字 (例如, {d1} 代表当天的日期号为一, 等等)。"锚点" 名紧随一个布尔类型值, 定义 EA 是否能够在相应的日子里进行交易 (在我们的例子里, 它表示在 d1 不可进行交易)。如果没有交易, 以下数值可以忽略, 但它们依然要保留。最后, 末尾的两个整数值代表 EA 的操作开始和结束时刻。在日线蜡烛开盘时, EA 读取新一天的操作日程。当然, 每天的数据字符串可依据操作逻辑以其它值修改和补充。因此, 只有当日数据存储在存储器中。您可以任意设置 "锚点" 名称, 但我建议使用有意义的。给 "锚点" 分配一个抽象名字无关紧要。相反, ta们应能够传达一定的意义并同时保持独特。请记住, 数据搜索是通过名字执行的。根据一个特定实现, 单一文件可以拥有若干相同名称的 "锚点"。赫兹期货量化来审查取自完整操作指标的代码片段。该指标需要若干货币对的数据以便进行正确地操作。所以, 它定期请求数据并按照其逻辑处理它 (指标逻辑在此对于我们不重要)。请记住, 券商有时候在品名上添加不同的后缀和前缀 (例如, EURUSD 也许转换为 #.EURUSD.ch)。这个应予考虑, 以便 EA 能够正确参照其它品名。我们的行动的顺序如下。1. 创建一个文本文件 broker.cfg 内容如下: [PREFIX_SUFFIX],#.,.ch2. 创建一个文本文件<indicator_name>.cfg内容如下:/*货币对的数量, 带有 "锚点" 字符串 [CHARTNAMES] */[CHARTCOUNT],7/*货币对名称, 其图表由指标读取数据*/[CHARTNAMES],USDCAD,AUDCAD,NZDCAD,GBPCAD,EURCAD,CADCHF,CADJPY/*在货币对中基础货币的位置 (在此情况下它是 CAD) – 第一个或第二个*/[DIRECT],0,0,0,0,0,1,13. 将两个文件放入 "沙盒"。4. 在指标代码里定义定义若干辅助函数 (或包含 ConfigFiles.mqh 文件):// 按照指定名称打开文件, 比如 CSV 文件并返回其句柄 int __OpenConfigFile(string name) { int h= FileOpen(name,FILE_READ|FILE_SHARE_READ|FILE_CSV,','); if(h == INVALID_HANDLE) PrintFormat("无效文件名 %s",name); return (h); }//+-------------------------------------------------------------------------------------+//| 函数在包含的分区里读取一个长整数型的 iRes 值 |//| strSec "锚点" 名 位于句柄文件内。如果成功, |//| 返回 true, 否则 – false。 |//+-------------------------------------------------------------------------------------+ bool _ReadIntInConfigSection(string strSec,int handle,long &iRes) { if(!FileSeek(handle,0,SEEK_SET) ) return (false); string s; while(!FileIsEnding(handle)) { if(StringCompare(FileReadString(handle),strSec)==0) { iRes=StringToInteger(FileReadString(handle)); return (true); } } return (false); }//+-------------------------------------------------------------------------------------+//| 函数在包含的分区里读取已计算长度的 sArray |//| strSec 在句柄文件内的 "锚点" 名。如果成功, |//| 返回 true, 否则 – false。 |//+-------------------------------------------------------------------------------------+ bool _ReadStringArrayInConfigSection(string strSec,int handle,string &sArray[],int count) { if(!FileSeek(handle,0,SEEK_SET) ) return (false); while(!FileIsEnding(handle)) { if(StringCompare(FileReadString(handle),strSec)==0) { ArrayResize(sArray,count); for(int i=0; i<count; i++) sArray[i]=FileReadString(handle); return (true); } } return (false); }//+-------------------------------------------------------------------------------------+//| 函数在包含的分区里读取已计算长度的布尔型 bArray |//| strSec 在句柄文件内的 "锚点" 名。如果成功, |//| 返回 true, 否则 – false。 |//+-------------------------------------------------------------------------------------+ bool _ReadBoolArrayInConfigSection(string strSec,int handle,bool &bArray[],int count) { string sArray[]; if(!_ReadStringArrayInConfigSection(strSec, handle, sArray, count) ) return (false); ArrayResize(bArray,count); for(int i=0; i<count; i++) { bArray[i]=(bool)StringToInteger(sArray[i]); } return (true); }a
使用标准工具来创建很少改变或根本不会改变的参数 (即, 订单魔幻数字或滑点值)。
如果在指标或 EA 的属性里, 从诸如 RSI, WPR 等十几款指标里选择唯一的一款指标作为数据源, 那么其中每款指标的所需参数均应在属性窗口里创建并可用, 尽管事实上我们仅需其中一套参数。这种类型的另一个例子是每周的 EA 操作日程。在周三时没必要保存周一和周二 (或周五) 相关的日期。但我们不得不这样做, 因为整个日程表位于输入部分。换言之, 在参数里描述动态创建的对象十分困难, 且是效率低下的任务。
如果我们需要在工具的属性列表中放置一张便条, 注释或题头, 赫兹期货量化要创建一个带有相应内容的新字符串属性。在某些时候这很不方便。
![](http://tiebapic.baidu.com/forum/w%3D580/sign=82bbadfcba039245a1b5e107b794a4a8/47056b540923dd54173bfc599709b3de9c824849.jpg?tbpicau=2024-06-26-05_491c9bd83e1ac0a1abe6aee4aae28421)
此处, "锚点" 名反映周内日期数, 使用确定的数字 (例如, {d1} 代表当天的日期号为一, 等等)。"锚点" 名紧随一个布尔类型值, 定义 EA 是否能够在相应的日子里进行交易 (在我们的例子里, 它表示在 d1 不可进行交易)。如果没有交易, 以下数值可以忽略, 但它们依然要保留。最后, 末尾的两个整数值代表 EA 的操作开始和结束时刻。在日线蜡烛开盘时, EA 读取新一天的操作日程。当然, 每天的数据字符串可依据操作逻辑以其它值修改和补充。因此, 只有当日数据存储在存储器中。您可以任意设置 "锚点" 名称, 但我建议使用有意义的。给 "锚点" 分配一个抽象名字无关紧要。相反, ta们应能够传达一定的意义并同时保持独特。请记住, 数据搜索是通过名字执行的。根据一个特定实现, 单一文件可以拥有若干相同名称的 "锚点"。赫兹期货量化来审查取自完整操作指标的代码片段。该指标需要若干货币对的数据以便进行正确地操作。所以, 它定期请求数据并按照其逻辑处理它 (指标逻辑在此对于我们不重要)。请记住, 券商有时候在品名上添加不同的后缀和前缀 (例如, EURUSD 也许转换为 #.EURUSD.ch)。这个应予考虑, 以便 EA 能够正确参照其它品名。我们的行动的顺序如下。1. 创建一个文本文件 broker.cfg 内容如下: [PREFIX_SUFFIX],#.,.ch2. 创建一个文本文件<indicator_name>.cfg内容如下:/*货币对的数量, 带有 "锚点" 字符串 [CHARTNAMES] */[CHARTCOUNT],7/*货币对名称, 其图表由指标读取数据*/[CHARTNAMES],USDCAD,AUDCAD,NZDCAD,GBPCAD,EURCAD,CADCHF,CADJPY/*在货币对中基础货币的位置 (在此情况下它是 CAD) – 第一个或第二个*/[DIRECT],0,0,0,0,0,1,13. 将两个文件放入 "沙盒"。4. 在指标代码里定义定义若干辅助函数 (或包含 ConfigFiles.mqh 文件):// 按照指定名称打开文件, 比如 CSV 文件并返回其句柄 int __OpenConfigFile(string name) { int h= FileOpen(name,FILE_READ|FILE_SHARE_READ|FILE_CSV,','); if(h == INVALID_HANDLE) PrintFormat("无效文件名 %s",name); return (h); }//+-------------------------------------------------------------------------------------+//| 函数在包含的分区里读取一个长整数型的 iRes 值 |//| strSec "锚点" 名 位于句柄文件内。如果成功, |//| 返回 true, 否则 – false。 |//+-------------------------------------------------------------------------------------+ bool _ReadIntInConfigSection(string strSec,int handle,long &iRes) { if(!FileSeek(handle,0,SEEK_SET) ) return (false); string s; while(!FileIsEnding(handle)) { if(StringCompare(FileReadString(handle),strSec)==0) { iRes=StringToInteger(FileReadString(handle)); return (true); } } return (false); }//+-------------------------------------------------------------------------------------+//| 函数在包含的分区里读取已计算长度的 sArray |//| strSec 在句柄文件内的 "锚点" 名。如果成功, |//| 返回 true, 否则 – false。 |//+-------------------------------------------------------------------------------------+ bool _ReadStringArrayInConfigSection(string strSec,int handle,string &sArray[],int count) { if(!FileSeek(handle,0,SEEK_SET) ) return (false); while(!FileIsEnding(handle)) { if(StringCompare(FileReadString(handle),strSec)==0) { ArrayResize(sArray,count); for(int i=0; i<count; i++) sArray[i]=FileReadString(handle); return (true); } } return (false); }//+-------------------------------------------------------------------------------------+//| 函数在包含的分区里读取已计算长度的布尔型 bArray |//| strSec 在句柄文件内的 "锚点" 名。如果成功, |//| 返回 true, 否则 – false。 |//+-------------------------------------------------------------------------------------+ bool _ReadBoolArrayInConfigSection(string strSec,int handle,bool &bArray[],int count) { string sArray[]; if(!_ReadStringArrayInConfigSection(strSec, handle, sArray, count) ) return (false); ArrayResize(bArray,count); for(int i=0; i<count; i++) { bArray[i]=(bool)StringToInteger(sArray[i]); } return (true); }a