交易者生活窍门: 利用 defines (#define) 融合 ForEach
编译时会导致难以检测的错误。循环随处环绕着我们: 搜索订单, 历史交易, 图表对象, 市场观察品种, 指标缓冲区中的柱线。问题出于 'for' 循环中 s = SymbolName (i, true) 表达式要在迭代之后计算, 且我们的 's' 变量在 i=0 的首次迭代时并未初始化。现在, 我们需要创建类似的宏定义来处理交易实例 — 订单, 仓位和交易。注意: 用 Point(), Digits
一名好的程序员是一位懒惰的程序员
创建智能交易系统几乎总是需要大量的循环工作。 循环随处环绕着我们: 搜索订单, 历史交易, 图表对象, 市场观察品种, 指标缓冲区中的柱线。 为了让程序员的生活更轻松一点, MetaEditor 以 代码片段 (snippets) 为特色, 意即当您输入第一个字符时, 按 Tab 键后它们会自动变成一小段代码。 这就是 'for' 循环片段的工作原理:
不错, 但它尚未覆盖我们的所有需求。 考虑最简单的例子: 假设我们需要搜索市场观察内的所有品种。
int total=SymbolsTotal(true); for(int i=0;i<total;i++) { string symbol=SymbolName(i,true); PrintFormat("%d. %s",i+1,symbol); }
开发一段以 fes (for_each_symbol) 开头的 MetaEditor 代码片段并在以下部分展开感觉会很棒:
MetaEditor 中没有自定义代码片段, 因此我们将利用 "defines"。 #define 宏定义替代是由追求多个目标的懒惰又聪明的程序员发明的。 其便利性包括便于阅读和编写复用代码。
许多编程语言, 除了标准 for 循环外, 还有其变体, 例如: for(<typename> element:Collection) 或 for each (type identifier in expression)。 如果我们可以编写如下代码
for(ulong order_id in History) { 参照 order_id 工作 }
, 程序员的生活会更轻松一些。 您可以在互联网上找到这种方法的发对者和支持者。 在此我会告诉您如何用 #define 宏定义做类似的事情。
我们从一个简单的任务开始 - 获取所有市场观察内品种的名称。 我们向前直行, 编写如下的宏定义:
#define ForEachSymbol(s,i) string s; int total=SymbolsTotal(true); for(int i=0;i<total;i++,s=SymbolName(i,true)) //+------------------------------------------------------------------+ //| 脚本程序 start 函数 | //+------------------------------------------------------------------+ void OnStart() { //--- ForEachSymbol(symbol,index) { PrintFormat("%d. %s",index,symbol); } }
编译器完全理解这条语句没有返回错误。 我们按 F5 开始调试, 发现有问题:
1. (null) 2. GBPUSD 3. USDCHF 4. USDJPY ...
问题出于 'for' 循环中 s = SymbolName (i, true) 表达式要在迭代之后计算, 且我们的 's' 变量在 i=0 的首次迭代时并未初始化。 'for' 语句:
'for' 语句由三个表达式和一条可执行语句组成:
for(expression1; expression2; expression3) |
Expression1 表示循环初始化。 Expression2 — 检查循环完成情况。 如果它为 'true', 则 for 循环实体操作符会被执行。 重复一切, 直到 expression2 变成 'false'。 如果它为 'false', 则循环终止并略过之下的语句。 ExpressionЗ 则在 每次迭代之后 进行计算。
这个过程很简单。 我们来做几个编辑:
#define ForEachSymbol(s,i) string s=SymbolName(0,true); int total=SymbolsTotal(true); for(int i=1;i<total;i++,s=SymbolName(i,true)) //+------------------------------------------------------------------+ //| 脚本程序 start 函数 | //+------------------------------------------------------------------+ void OnStart() { //--- ForEachSymbol(symbol,index) { PrintFormat("%d. %s",index,symbol); // index+1 由 index 替代 } }
并获得必要的结果。 我们已经开发了带有 symbol 和 index 参数的 ForEachSymbol 宏定义, 就好像这是一个正常的 for 循环, 并且用这些变量处理伪循环体就好像它们已经使用必要的值进行了声明和初始化。 因此, 我们可以使用 SymbolInfoXXX() 函数获得市场观察内品种的所需属性。 例如:
//+------------------------------------------------------------------+ //| 脚本程序 start 函数 | //+------------------------------------------------------------------+ void OnStart() { //--- ForEachSymbol(symbol,index) { //--- 准备数据 double spread=SymbolInfoDouble(symbol,SYMBOL_ASK)-SymbolInfoDouble(symbol,SYMBOL_BID); double point=SymbolInfoDouble(symbol,SYMBOL_POINT); long digits=SymbolInfoInteger(symbol,SYMBOL_DIGITS); string str_spread=DoubleToString(spread/point,0); string str_point=DoubleToString(point,digits); //--- 显示数据 Print(index,". ",symbol," spread=",str_spread," points (", digits," digits",", point=",str_point,")"); } /* 简单输出 1. EURUSD spread=3 points (5 digits, point=0.00001) 2. USDCHF spread=8 points (5 digits, point=0.00001) 3. USDJPY spread=5 points (3 digits, point=0.001) 4. USDCAD spread=9 points (5 digits, point=0.00001) 5. AUDUSD spread=5 points (5 digits, point=0.00001) 6. NZDUSD spread=10 points (5 digits, point=0.00001) 7. USDSEK spread=150 points (5 digits, point=0.00001) */ }
现在我们可以编写一个类似的宏定义来搜索图表上的图形对象:
#define ForEachObject(name,i) string name=ObjectName(0,0); int total=ObjectsTotal(0); for(int i=1;i<=total;i++,name=ObjectName(0,i-1)) //+------------------------------------------------------------------+ //| 脚本程序 start 函数 | //+------------------------------------------------------------------+ void OnStart() { //--- ForEachObject(objectname,index) { Print(index,": objectname=\"",objectname,"\", objecttype=", EnumToString((ENUM_OBJECT)ObjectGetInteger(0,objectname,OBJPROP_TYPE))); } /* 简单输出 1: objectname="H1 Arrow 61067", objecttype=OBJ_ARROW_UP 2: objectname="H1 Rectangle 31152", objecttype=OBJ_RECTANGLE 3: objectname="H1 StdDev Channel 56931", objecttype=OBJ_STDDEVCHANNEL 4: objectname="H1 Trendline 6605", objecttype=OBJ_TREND */ }
ForEachObject 宏定义字符串变得有点长了。 此外, 理解单一字符串替换的代码更加困难。 但事实证明, 这个问题已经得到解决: 现在可以使用反斜杠 '\' 将宏定义切分为多个字符串。 结果如下:
#define ForEachObject(name,i) string name=ObjectName(0,0); \ int ob_total=ObjectsTotal(0); \ for(int i=1;i<=ob_total;i++,name=ObjectName(0,i-1))
对于编译器来说, 所有这三个字符串看起来像一个单一的长字符串, 同时变得更容易理解。 现在, 我们需要创建类似的宏定义来处理交易实例 — 订单, 仓位和交易。
我们从搜索订单开始。 在此仅添加 HistorySelect() 历史选择函数:
#define ForEachOrder(ticket,i) HistorySelect(0,TimeCurrent()); \ ulong ticket=OrderGetTicket(0); \ int or_total=OrdersTotal(); \ for(int i=1;i<or_total;i++,ticket=OrderGetTicket(i)) //+------------------------------------------------------------------+ //| 脚本程序 start 函数 | //+------------------------------------------------------------------+ void OnStart() { //--- ForEachOrder(orderticket,index) { Print(index,": #",orderticket," ",OrderGetString(ORDER_SYMBOL)," ", EnumToString((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE))); } /* 简单输出 1: #13965457 CADJPY ORDER_TYPE_SELL_LIMIT 2: #14246567 AUDNZD ORDER_TYPE_SELL_LIMIT */ }
您可以注意到这个宏定义中没有错误处理 (以及前两个)。 例如, 如果 HistorySelect() 返回 false 会怎样? 在这种情况下, 我们将无法在循环中遍历所有的订单。 另外, 是谁在真正分析 HistorySelect() 的执行结果? 因此, 这个宏定义没有包含任何可能被禁止用于开发程序的常用方式。
对于 #define 最强烈的批评是 代码调试 中不允许使用宏替换。 我同意这一点, 但正如 fxsaber 所说: "已康复患者不需要麻醉 已调试宏定义不需要再进行调试"。
接下来, 我们以类似的方式开发用于搜索仓位的宏定义:
#define ForEachPosition(ticket,i) HistorySelect(0,TimeCurrent()); \ ulong ticket=PositionGetTicket(0); \ int po_total=PositionsTotal(); \ for(int i=1;i<=po_total;i++,ticket=PositionGetTicket(i-1)) //+------------------------------------------------------------------+ //| 脚本程序 start 函数 | //+------------------------------------------------------------------+ void OnStart() { //--- ForEachPosition(positionid,index) { Print(index,": ",PositionGetString(POSITION_SYMBOL)," postionID #",positionid); } /* 简单输出 1: AUDCAD postionID #13234934 2: EURNZD postionID #13443909 3: AUDUSD postionID #14956799 4: EURUSD postionID #14878673 */
搜索历史中的交易:
#define ForEachDeal(ticket,i) HistorySelect(0,TimeCurrent()); \ ulong ticket=HistoryDealGetTicket(0); \ int total=HistoryDealsTotal(); \ for(int i=1;i<=total;i++,ticket=HistoryDealGetTicket(i-1)) //+------------------------------------------------------------------+ //| 脚本程序 start 函数 | //+------------------------------------------------------------------+ void OnStart() { //--- ForEachDeal(dealticket,index) { Print(index,": deal #",dealticket,", order ticket=", HistoryDealGetInteger(dealticket,DEAL_ORDER)); } }
搜索历史中的订单:
#define ForEachHistoryOrder(ticket,i) HistorySelect(0,TimeCurrent());\ ulong ticket=HistoryOrderGetTicket(0); \ int total=HistoryOrdersTotal(); \ for(int i=1;i<=total;i++,ticket=HistoryOrderGetTicket(i-1)) //+------------------------------------------------------------------+ //| 脚本程序 start 函数 | //+------------------------------------------------------------------+ void OnStart() { //--- ForEachHistoryOrder(historyorderticket,index) { Print(index,": #",historyorderticket); } }
在一个 ForEach.mqh4 文件中收集所有宏替换:
//+------------------------------------------------------------------+ //| ForEach.mqh | //| 版权所有 2018, MetaQuotes 软件公司 | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "版权所有 2018, MetaQuotes 软件公司" #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| 市场观察搜索循环 | //+------------------------------------------------------------------+ #define ForEachSymbol(symbol,i) string symbol=SymbolName(0,true); \ int os_total=SymbolsTotal(true); \ for(int i=1;i<os_total;i++,symbol=SymbolName(i,true)) //+------------------------------------------------------------------+ //| 搜索图表主窗口对象循环 | //+------------------------------------------------------------------+ #define ForEachObject(name,i) string name=ObjectName(0,0); \ int ob_total=ObjectsTotal(0); \ for(int i=1;i<=ob_total;i++,name=ObjectName(0,i-1)) //+------------------------------------------------------------------+ //| 搜索活跃订单循环 | //+------------------------------------------------------------------+ #define ForEachOrder(ticket,i) HistorySelect(0,TimeCurrent()); \ ulong ticket=OrderGetTicket(0); \ int or_total=OrdersTotal(); \ for(int i=1;i<or_total;i++,ticket=OrderGetTicket(i)) //+------------------------------------------------------------------+ //| 搜索持仓循环 | //+------------------------------------------------------------------+ #define ForEachPosition(ticket,i) HistorySelect(0,TimeCurrent()); \ ulong ticket=PositionGetTicket(0); \ int po_total=PositionsTotal(); \ for(int i=1;i<=po_total;i++,ticket=PositionGetTicket(i-1)) //+------------------------------------------------------------------+ //| 搜索历史交易循环 | //+------------------------------------------------------------------+ #define ForEachDeal(ticket,i) HistorySelect(0,TimeCurrent()); \ ulong ticket=HistoryDealGetTicket(0); \ int dh_total=HistoryDealsTotal(); \ for(int i=1;i<=dh_total;i++,ticket=HistoryDealGetTicket(i-1)) //+------------------------------------------------------------------+ //| 搜索历史订单循环 | //+------------------------------------------------------------------+ #define ForEachHistoryOrder(ticket,i) HistorySelect(0,TimeCurrent());\ ulong ticket=HistoryOrderGetTicket(0); \ int oh_total=HistoryOrdersTotal(); \ for(int i=1;i<=oh_total;i++,ticket=HistoryOrderGetTicket(i-1)) //+------------------------------------------------------------------+
注意: 我们必须为每个宏定义的 'total' 变量添加一个 前缀, 这样的话如果我们决定在代码中使用多个宏定义, 就不会有冲突。 这是宏定义的最大缺点: 我们将变量声明隐藏其内, 而变量从外部可见。 编译时会导致难以检测的错误。
另外, 当使用参数宏时, 编译器不会像函数那样给出任何提示。 如果您想使用它们, 您必须用心学习这 6 个宏定义。 虽然这并不太难, 但是因为 第一个参数 总是一个循环的实例, 而第二个参数总是从 1 开始的循环索引。
最后, 我们添加更多反向搜索的宏定义。 在这种情况下, 我们需要从列表的末尾开始。 将 Back 后缀添加到宏定义名称并进行一些微小的修改。 以下是搜索市场观察内品种的宏定义。
#define ForEachSymbolBack(symbol,i) int s_start=SymbolsTotal(true)-1;\ string symbol=SymbolName(s_start,true); \ for(int i=s_start;i>=0;i--,symbol=SymbolName(i,true)) //+------------------------------------------------------------------+ //| 脚本程序 start 函数 | //+------------------------------------------------------------------+ void OnStart() { //--- ForEachSymbolBack(symbol,index) { //--- 准备数据 double spread=SymbolInfoDouble(symbol,SYMBOL_ASK)-SymbolInfoDouble(symbol,SYMBOL_BID); double point=SymbolInfoDouble(symbol,SYMBOL_POINT); long digits=SymbolInfoInteger(symbol,SYMBOL_DIGITS); string str_spread=DoubleToString(spread/point,0); string str_point=DoubleToString(point,digits); //--- 输出数据 Print(index,". ",symbol," spread=",str_spread," points (", digits," digits",", point=",str_point,")"); } /* 简单输出 3. USDJPY spread=5 points (3 digits, point=0.001) 2. USDCHF spread=8 points (5 digits, point=0.00001) 1. GBPUSD spread=9 points (5 digits, point=0.00001) 0. EURUSD spread=2 points (5 digits, point=0.00001) */ }
如您所见, index 变量的值在此处从 size-1 变化为 0。 我们已经完成了对 #define 的了解。 现在, 是时候开发用于简单 MQL4 风格访问的函数了。
1. 本文中描述了哪些 MQL4 函数组
注意: 用 Point(), Digits() 和 Bar(Symbol(),Period()) 替换 Point, Digits 和 Bar 等变量。
MQL4 AccountXXXX, MQL4 MarketInfo, MQL4 状态检查和 MQL4 预定义变量组将被转换为 MQL5。 所以, 四个文件: AccountInfo.mqh, MarketInfo.mqh, Check.mqh 和 Predefined.mqh 要添加到 [数据文件夹]\MQL5\Include\SimpleCall\。 文件夹中有七个文件要从 MQL4 函数转换为 MQL5: AccountInfo.mqh, Check.mqh, IndicatorsMQL4.mqh, IndicatorsMQL5.mqh, MarketInfo.mqh, Predefined.mqh 和 Series.mqh。
您应该包含所有这些文件。 此外, 请注意限制: IndicatorsMQL4.mqh 和 IndicatorsMQL5.mqh 文件不能一同包含 — 您只能从中选择其一。 因此, 该文件夹有两个文件: SimpleCallMQL4.mqh 包含所有文件加上 IndicatorsMQL4.mqh 以及 SimpleCallMQL5.mqh 包含所有文件加上 IndicatorsMQL5.mqh。
包含基于 MACD Sample.mq4 的示例
与 EA 一同将 MACD Sample.mq4 复制到 MQL5 文件夹 — 例如, [数据文件夹]\MQL5\Experts\, 并将文件扩展名更改为 mq5。 所以, 我们得到 MACD Sample.mq5 文件。 编译并得到 59 个错误和一个警告。
现在, 连接 SimpleCallMQL4.mqh:
//+------------------------------------------------------------------+ //| MACD Sample.mq4 | //| 版权所有 2005-2014, MetaQuotes 软件公司 | //| http://www.mql4.com | //+------------------------------------------------------------------+ #property copyright "2005-2014, MetaQuotes 软件公司" #property link "http://www.mql4.com" //--- #include <SimpleCall\SimpleCallMQL4.mqh> //--- input double TakeProfit =50;
再次编译并得到 39 个错误和一个警告。 现在, 手工 (Ctrl+H) 用 Bars(Symbol(),Period()) 替换 Bars, 以及用 Point() 替换 Point。 编译。 还剩 35 个错误。 它们都与交易函数有关。 但我们不会在本文中讨论交易函数。
1.1. MQL4 AccountXXXX
MQL4 AccountXXXX 函数已在文件中转换 [数据文件夹]\MQL5\Include\SimpleCall\AccountInfo.mqh
与 MQL4 函数匹配的 MQL5 函数的表格如下所示:
MQL4 | MQL5 AccountInfoXXXX | MQL5 CAccountInfo | 注意 |
---|---|---|---|
AccountInfoDouble | AccountInfoDouble | CAccountInfo::InfoDouble 或 CAccountInfo::double 方法 | |
AccountInfoInteger | AccountInfoInteger | CAccountInfo::InfoInteger 或 CAccountInfo::integer 方法 | |
AccountInfoString | AccountInfoString | CAccountInfo::InfoString 或 CAccountInfo::text 方法 | |
AccountBalance | AccountInfoDouble(ACCOUNT_BALANCE) 或 | CAccountInfo::Balance | |
AccountCredit | AccountInfoDouble(ACCOUNT_CREDIT) 或 | CAccountInfo::Credit | |
AccountCompany | AccountInfoString(ACCOUNT_COMPANY) 或 | CAccountInfo::Company | |
AccountCurrency | AccountInfoString(ACCOUNT_CURRENCY) 或 | CAccountInfo::Currency | |
AccountEquity | AccountInfoDouble(ACCOUNT_EQUITY) 或 | CAccountInfo::Equity | |
AccountFreeMargin | AccountInfoDouble(ACCOUNT_FREEMARGIN) 或 | CAccountInfo::FreeMargin | |
AccountFreeMarginCheck | --- /--- | CAccountInfo::FreeMarginCheck | |
AccountFreeMarginMode | 无等价品 | 无等价品 | |
AccountLeverage | AccountInfoInteger(ACCOUNT_LEVERAGE) | CAccountInfo::Leverage | 在 MQL4 中, 它是 int 类型, 而在 MQL5 中, 它是 long |
AccountMargin | AccountInfoDouble(ACCOUNT_MARGIN) | CAccountInfo::Margin | |
AccountName | AccountInfoString(ACCOUNT_NAME) | CAccountInfo::Name | |
AccountNumber | AccountInfoInteger(ACCOUNT_LOGIN) | CAccountInfo::Login | 在 MQL4 中, 它是 int 类型, 而在 MQL5 中, 它是 long |
AccountProfit | AccountInfoDouble(ACCOUNT_PROFIT) | CAccountInfo::Profit | |
AccountServer | AccountInfoString(ACCOUNT_SERVER) | CAccountInfo::Server | |
AccountStopoutLevel | AccountInfoDouble(ACCOUNT_MARGIN_SO_SO) | CAccountInfo::MarginStopOut | 在 MQL4 中, 它是 int 类型, 而在 MQL5 中, 它是 double |
AccountStopoutMode | AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE) | CAccountInfo::StopoutMode |
请注意, MQL5 没有匹配 MQL4 AccountFreeMarginMode 的等价品。 您使用 MQL4 AccountFreeMarginMode 则风险自负。 当检测到 MQL4 AccountFreeMarginMode 时, 会向日志发送警告, 并返回 NaN ("非数字")。
对于其它 MQL4 AccountXXXX 函数, 有两个版本的等价品: 通过 AccountInfoXXXX 或通过 CAccountInfo 交易类。 对于 AccountInfoDouble, AccountInfoInteger 和 AccountInfoString, MQL4 和 MQL5 之间没有区别。
文件头有以下代码。 如何工作?
//--- #define OP_BUY ORDER_TYPE_BUY #define OP_SELL ORDER_TYPE_SELL //--- 返回当前帐户的余额值
首先, 我们来看看 #define help:
#define 指令可用于将常用名称分配给常量。 有两种形式:
#define identifier expression // 无参数形式 #define identifier(par1,... par8) expression // 参数形式
#define 指令在源文本中将所有发现的 "identifier" 替换为 "expression"。
在我们的代码中, 这些描述看起来如下 (我们使用了无参数形式): #define 指令以 ORDER_TYPE_BUY 替换所有在源文件中发现的 OP_BUY。 #define 指令以 ORDER_TYPE_SELL 替换所有在源文件中发现的 OP_SELL。 换言之, 将文件 [数据文件夹]\MQL5\Include\SimpleCall\AccountInfo.mqh 包含到您的 MQL5 EA 之后, 您能够按照类似的方式使用 OP_BUY 和 OP_SELL MQL4 类型。 编译器不会返回错误。
因此, 我们为 MQL5 类型带来了第一组函数: AccountBalance(), AccountCredit(), AccountCompany(), AccountCurrency(), AccountEquity() 和 AccountFreeMargin():
//--- 返回当前帐户的余额值 #define AccountBalance(void) AccountInfoDouble(ACCOUNT_BALANCE) //--- 返回当前帐户的信用值 #define AccountCredit(void) AccountInfoDouble(ACCOUNT_CREDIT) //--- 返回当前帐户注册的经纪公司名称 #define AccountCompany(void) AccountInfoString(ACCOUNT_COMPANY) //--- 返回当前帐户的货币名称 #define AccountCurrency(void) AccountInfoString(ACCOUNT_CURRENCY) //--- 返回当前账户的净值 #define AccountEquity(void) AccountInfoDouble(ACCOUNT_EQUITY) //--- 返回当前帐户的可用保证金 #define AccountFreeMargin(void) AccountInfoDouble(ACCOUNT_MARGIN_FREE)
此处, 在 MQL4 XXXX(void) 函数中, 使用参数化的 #define 形式, 其中 "void" 充当参数。 这可以很容易地检查: 如果我们删除 "void", 编译期间出现 "unexpected in macro format parameter list" 错误:
在 MQL4 AccountFreeMarginCheck 的情况下, 我们将采取不同的行动 — 将 AccountFreeMarginCheck 设置为正常函数, 仅使用其中的 MQL5 代码:
//--- 返回指定订单打开后剩余的可用保证金 //--- 按当前账户的当前价格计算 double AccountFreeMarginCheck(string symbol,int cmd,double volume) { double price=0.0; ENUM_ORDER_TYPE trade_operation=(ENUM_ORDER_TYPE)cmd; if(trade_operation==ORDER_TYPE_BUY) price=SymbolInfoDouble(symbol,SYMBOL_ASK); if(trade_operation==ORDER_TYPE_SELL) price=SymbolInfoDouble(symbol,SYMBOL_BID); //--- double margin_check=EMPTY_VALUE; double margin=EMPTY_VALUE; margin_check=(!OrderCalcMargin(trade_operation,symbol,volume,price,margin))?EMPTY_VALUE:margin; //--- return(AccountInfoDouble(ACCOUNT_FREEMARGIN)-margin_check); }
正如我们上面所说的, AccountFreeMarginMode 在 MQL5 中没有等价品, 因此, 在代码中检测到 AccountFreeMarginMode 时, 会发出 "非数字 (not a number)" 和警告:
//--- 返回当前账户上开单的可用保证金计算模式 double AccountFreeMarginMode(void) { string text="MQL4 functions \"AccountFreeMarginMode()\" has no analogs in MQL5. Returned \"NAN - not a number\""; Alert(text); Print(text); return(double("nan")); }
对于其它 MQL4 函数, 我们以类似的方式进行:
//--- 返回当前账户的杠杆 #define AccountLeverage(void) (int)AccountInfoInteger(ACCOUNT_LEVERAGE) //--- 返回当前帐户的保证金 #define AccountMargin(void) AccountInfoDouble(ACCOUNT_MARGIN) //--- 返回当前帐户名称 #define AccountName(void) AccountInfoString(ACCOUNT_NAME) //--- 返回当前帐号 #define AccountNumber(void) (int)AccountInfoInteger(ACCOUNT_LOGIN) //--- 返回当前帐户的利润值 #define AccountProfit(void) AccountInfoDouble(ACCOUNT_PROFIT) //--- 返回连接的服务器名称 #define AccountServer(void) AccountInfoString(ACCOUNT_SERVER) //--- 返回强制平仓级别的数值 #define AccountStopoutLevel(void) (int)AccountInfoDouble(ACCOUNT_MARGIN_SO_SO) //--- 返回强制平仓级别的计算模式 int AccountStopoutMode(void) { ENUM_ACCOUNT_STOPOUT_MODE stopout_mode=(ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE); if(stopout_mode==ACCOUNT_STOPOUT_MODE_PERCENT) return(0); return(1); }
更多推荐
所有评论(0)