初学者的问题 MQL5 MT5 MetaTrader 5 - 页 1415

 
  1. 大多数经纪商不再追缴保证金,因为所有头寸都会在账户亏损前(自动?)平仓(您必须追加资金:追缴保证金)。
  2. 保证金是未平仓合约的保证金,ACCOUNT_MARGIN_FREE 是剩余部分(未使用部分)。
  3. 账户余额(余额)或资本余额(账户余额 + 未结头寸,股本)最多有 5%-10%用于交易,以防止因资本不足和头寸亏损而平仓。
  4. 头寸的风险取决于 SL 和手数,因为出于技术原因,SL 通常是固定的,手数用于计算风险:
    搜索 "计算手数": https://www.mql5.com/en/search#!keyword=calculate%20lotsize&module=mql5_module_forum
  5. 提示 大多数文章也有德文版,只需将 URL 中的/en/ 替换为/de/ https://www.mql5.com/de/articles/2555
 
感谢您提供信息。在交易机器人必须通过的检查 中,提到了 "CheckMoneyForTrade "方法,该方法用于检查用于交易的保证金是否大于自由保证金(ACCOUNT_FREE_MARGIN)。如果我没有理解错的话,那么您还应该检查所用资金是否也超过了账户余额的某个百分比,即类似于以下情况
 if (freeMargin - tradeMargin < balance * 0.9) return false;

当然,您可以将 0.9 改为 (1 - maxRisk),并实现一个可由用户设置的 "最大风险百分比 "属性。

附注:您在论坛上使用的是名还是姓?
 
Benjamin Fotteler #:
感谢您提供信息。在交易机器人必须通过的检查 中,提到了 "CheckMoneyForTrade "方法,该方法用于检查用于交易的保证金是否大于自由保证金(ACCOUNT_FREE_MARGIN)。如果我没有理解错的话,你还应该检查使用的资金是否也超过了账户余额的某个百分比,即类似的百分比:

当然,您可以将 0.9 改为 (1 - maxRisk),并实现一个可由用户设置的 "最大风险百分比 "属性。

附注: 在论坛上,我们是以名字相称还是以名字相称?

每个人都对手数大小耿耿于怀,这里有很多代码和评论!

我现在已经弄明白了 William Roeder 为 MT5 写的东西,那就是未经测试的(!!)函数:
(https://www.mql5.com/en/forum/133792/page3#comment_3405179&https://www.mql5.com/en/forum/390088#comment_28092477)

double lotsz (double risk, double sl, ENUM_ORDER_TYPE ordDir, string sym="", double CommissionPerLot=0) {
   MqlTick mqTick;
   if (sym == "") sym = _Symbol;
   double deltaValue = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE) / SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
   SymbolInfoTick(sym,mqTick); 
   double diff = (ordDir==ORDER_TYPE_BUY) ? mqTick.ask - sl : ( (ordDir==ORDER_TYPE_SELL) ? sl - mqTick.bid : -1.0 );
   if (diff<0.0) return(0.0);
   double lts = ( (AccountInfoDouble(ACCOUNT_MARGIN_FREE) * risk/100) / (diff * deltaValue + CommissionPerLot) );
   return( fmin(fmax(SymbolInfoDouble(sym,SYMBOL_VOLUME_MIN),lts),SymbolInfoDouble(sym,SYMBOL_VOLUME_MAX)));
}
// use: lotsz(5, sl)

如果您发现错误,请告诉我!

由于这里大多数人的昵称或名字都是匿名的,以前更是如此,所以 "Du "已经成为一种习惯。

Why is there NO Complete EA within the Code-Base? - When does the market close or open?
Why is there NO Complete EA within the Code-Base? - When does the market close or open?
  • 2011.08.20
  • www.mql5.com
I wanted to close all orders before end of the week (market close friday,) to prevent loss should the market gap over the week end, by passing the sl. ) so the question is when does the market close (or open. For example info on opened charts and history data, time info (like gmt, timezone, dst), market open, close info
 

感谢您提供的代码。唯一缺少的就是适应有效的中间批量大小:

double lotsz (double risk, double sl, ENUM_ORDER_TYPE ordDir, string sym="", double CommissionPerLot=0) {
   MqlTick mqTick;
   if (sym == "") sym = _Symbol;
   double deltaValue = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE) / SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
   SymbolInfoTick(sym,mqTick); 
   double diff = (ordDir==ORDER_TYPE_BUY) ? mqTick.ask - sl : ( (ordDir==ORDER_TYPE_SELL) ? sl - mqTick.bid : -1.0 );
   if (diff<0.0) return(0.0);
   double lts = ( (AccountInfoDouble(ACCOUNT_MARGIN_FREE) * risk/100) / (diff * deltaValue + CommissionPerLot) );
   lts = ( fmin(fmax(SymbolInfoDouble(sym,SYMBOL_VOLUME_MIN),lts),SymbolInfoDouble(sym,SYMBOL_VOLUME_MAX)));
   double stepSize = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
   return ((int)MathRound(lts/stepSize)*stepSize);
}
// use: lotsz(5, sl)

我还有一个问题:如果我用 TICK_VALUE 或上述的 deltaValue 计算止损交易的损失,结果总是与 MQL5 的内部计算略有不同:

double price=(ordDir==ORDER_TYPE_BUY) ? mqTick.ask : ((ordDir==ORDER_TYPE_SELL) ? mqTick.bid : mqTick.last);
double loss;
OrderCalcProfit(ordDir, sym, 1, price, sl, loss)

这是否是因为欧元账户、市场价格 1.0 和市场价格 1.2 的每一个刻度点的损失/收益不同?例如,如果我在下面的代码中输入 "price + 0.1 "而不是 price,输入 "sl + 0.1 "而不是 sl,那么跳动距离 (diff) 是相同的,但OrderCalcProfit 输出的结果却不同。当我查看手动交易的利润/亏损时,后者似乎得到了证实。

如果我是对的,那么下面的代码会更准确:

double lotsz (double risk, double entry, double sl, ENUM_ORDER_TYPE ordDir, string sym="", double CommissionPerLot=0) {
   if (sym == "") sym = _Symbol;
   double loss;
   OrderCalcProfit(ordDir, sym, 1, entry, sl, loss);
   double lts = ((AccountInfoDouble(ACCOUNT_MARGIN_FREE) * risk * 0.01) / -loss);
   lts = (fmin(fmax(SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN), lts), SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX)));
   double stepSize = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
   return ((int)MathRound(lts / stepSize) * stepSize);
}
// use: lotsz(5, ask, sl)
附注:再次感谢您提供的基本思路:将风险系数不与余额挂钩,而是与自由保证金挂钩显然是有道理的。
 

下面的代码是根据 mql 5 自带的抛物线萨专家创建的。我是否可以在这里反转买入信号和卖出信号的操作? 也就是说,当买入信号出现时,我想让它打开卖出而不是买入。有人能帮忙吗?




#property copyright "MetaQuotes有限公司版权所有2022"。

#property link"https://www.mql5.com"

#property version "1.00"

//+------------------------------------------------------------------+

//| 包括 |

//+------------------------------------------------------------------+

#include <Expert\Expert.mqh>

//--- 可用信号

#include <Expert\Signal\SignalSAR.mqh> //--- 可用的信号

//--- 可用的尾音

#include <Expert\Trailing\TrailingNone.mqh

//--- 可用的资金管理

#include <Expert\Money\MoneyFixedLot.mqh

//+------------------------------------------------------------------+

//| Inputs | //++

//+------------------------------------------------------------------+

//--- 专家输入

输入字符串 Expert_Title ="sar"; // 文档名称

ulong Expert_MagicNumber =13831; //

bool Expert_EveryTick =false; //

//--- 主信号输入

input int Signal_ThresholdOpen =10; // 打开的信号阈值 [0...100]

input int Signal_ThresholdClose=10; // 关闭信号的阈值 [0...100] 输入

输入 double Signal_PriceLevel =0.0; // 执行交易的价格水平

输入 int Signal_Expiration =4; // 挂单有效期(以条为单位)

输入 double Signal_SAR_Step =0.02; // 抛物线 SAR(0.02,0.2) 速度增量

输入 double Signal_SAR_Maximum =0.2; // 抛物线 SAR(0.02,0.2) 最大速度

输入 double Signal_SAR_Weight =1.0; // 抛物线 SAR(0.02,0.2) 重量 [0....1.0]

//--- 资金输入

输入 double Money_FixLot_Percent =10.0; // 百分比

输入 double Money_FixLot_Lots =0.1; // 固定交易量

//+------------------------------------------------------------------+

//| 全局专家对象

//+------------------------------------------------------------------+

CExpert ExtExpert;

//+------------------------------------------------------------------+

// 专家的初始化函数

//+------------------------------------------------------------------+

int OnInit()

{

//--- 专家初始化

if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))

{

//----- 失败

printf(__FUNCTION__+": error initialising expert");

ExtExpert.Deinit();

return(INIT_FAILED);

}

//--- 创建信号

CExpertSignal *signal=new CExpertSignal;

if(signal==NULL)

{

//----- 失败

printf(__FUNCTION__+": error creating signal");

ExtExpert.Deinit();

return(INIT_FAILED);

}

//---

ExtExpert.InitSignal(signal);

signal.ThresholdOpen(Signal_ThresholdOpen);

signal.ThresholdClose(Signal_ThresholdClose);

signal.PriceLevel(Signal_PriceLevel);

signal.Expiration(Signal_Expiration);

//--- 创建 CSignalSAR 过滤器

CSignalSAR *filter0=new CSignalSAR;

if(filter0==NULL)

{

//----- 失败

printf(__FUNCTION__+": error creating filter0");

ExtExpert.Deinit();

return(INIT_FAILED);

}

signal.AddFilter(filter0);

//--- 设置过滤器参数

filter0.Step(Signal_SAR_Step);

filter0.Maximum(Signal_SAR_Maximum);

filter0.Weight(Signal_SAR_Weight);

//--- 创建拖尾对象

CTrailingNone *trailing=new CTrailingNone;

if(trailing==NULL)

{

//----- 失败

printf(__FUNCTION__+": error creating trailing");

ExtExpert.Deinit();

return(INIT_FAILED);

}

//--- 向专家添加拖尾(将自动删除))

if(!ExtExpert.InitTrailing(trailing))

{

//----- 失败

printf(__FUNCTION__+": error initialising trailing");

ExtExpert.Deinit();

return(INIT_FAILED);

}

//--- 设置拖尾参数

//--- 创建货币对象

CMoneyFixedLot *money=new CMoneyFixedLot;

if(money==NULL)

{

//----- 失败

printf(__FUNCTION__+": error creating money");

ExtExpert.Deinit();

return(INIT_FAILED);

}

//--- 向专家添加资金(将自动删除))

if(!ExtExpert.InitMoney(money))

{

//----- 失败

printf(__FUNCTION__+": error initialising money");

ExtExpert.Deinit();

return(INIT_FAILED);

}

//--- 设置货币参数

money.Percent(Money_FixLot_Percent);

money.Lots(Money_FixLot_Lots);

//--- 检查所有交易对象参数

if(!ExtExpert.ValidationSettings())

{

//----- 失败

ExtExpert.Deinit();

return(INIT_FAILED);

}

//--- 调整所有必要的指标

if(!ExtExpert.InitIndicators())

{

//----- 失败

printf(__FUNCTION__+": error initialising indicators");

ExtExpert.Deinit();

return(INIT_FAILED);

}

//--- ok

return(INIT_SUCCEEDED);

}

//+------------------------------------------------------------------+

// 专家的去初始化函数

//+------------------------------------------------------------------+

void OnDeinit(const int reason)

{

ExtExpert.Deinit();

}

//+------------------------------------------------------------------+

//| "Tick "事件处理函数

//+------------------------------------------------------------------+

void OnTick()

{

ExtExpert.OnTick();

}

//+------------------------------------------------------------------+

//| "交易 "事件处理函数

//+------------------------------------------------------------------+

void OnTrade()

{

ExtExpert.OnTrade();

}

//+------------------------------------------------------------------+

//| "定时器 "事件处理函数

//+------------------------------------------------------------------+

void OnTimer()

{

ExtExpert.OnTimer();

}

//+------------------------------------------------------------------+


 
有趣的建议,我会看看。OrderCalcProfit() 函数只存在于 MT5 中,而计算手数的想法可以追溯到 MT4 时代...
 
我无法在应用程序中打开我的会话,查看我有多少钱
 

我现在有时间研究一下您的解决方案。它更准确(而另一种则更谨慎,因为要考虑到佣金?),而且出错率显然更低,在MQ模拟账户的黄金和白银交易中可以看到这一点--在Roboforex交易中,正如所料,它比您的方案更谨慎:

MetaQuotes demo account (b. 3369 Beta channel)
2022.07.25 17:43:42.645 test_MM-functions (EURUSD,M1)   XAUUSD  in: 1717.65000 sl:1717.15000  diff:0.50000  delta:10.00000  delta:*diff:5.00000  tVal:0.10000  tSz:0.01000
2022.07.25 17:43:42.645 test_MM-functions (EURUSD,M1)   XAGUSD  in: 18.45100 sl:18.40100  diff:0.05000  delta:500.00000  delta:*diff:25.00000  tVal:0.50000  tSz:0.00100
2022.07.25 17:43:42.645 test_MM-functions (EURUSD,M1)   EURUSD  in: 1.02185 sl:1.02235  diff:0.00050  delta:97861.72139  delta:*diff:48.93086  tVal:0.97862  tSz:0.00001
2022.07.25 17:43:42.645 test_MM-functions (EURUSD,M1)   Set: Risk: 5.0 %, dSL: 50  Com/Lot: 2.00  Free: 9983.40 EUR:  XAUUSD  BU  in: 1717.65000  sl: 1717.15000  lotsC: 71.3100 (-3489.26)  lotsB: 10.2000 (-499.09)
2022.07.25 17:43:42.645 test_MM-functions (EURUSD,M1)   Set: Risk: 5.0 %, dSL: 50  Com/Lot: 2.00  Free: 9983.40 EUR:  XAGUSD  BU  in: 18.45100  sl: 18.40100  lotsC: 18.4900 (-4523.66)  lotsB: 2.0400 (-499.09)
2022.07.25 17:43:42.645 test_MM-functions (EURUSD,M1)   Set: Risk: 5.0 %, dSL: 50  Com/Lot: 2.00  Free: 9983.40 EUR:  EURUSD  SE  in: 1.02185  sl: 1.02235  lotsC: 9.8000 (-479.29)  lotsB: 10.2100 (-499.34)


RoboForex Demo account (b. 3320 release channel)
2022.07.25 17:46:22.772 test_MM-functions (EURUSD,D1)   XAUUSD  in: 1717.10000 sl:1717.15000  diff:0.05000  delta:100.00000  delta:*diff:5.00000  tVal:0.10000  tSz:0.00100
2022.07.25 17:46:22.772 test_MM-functions (EURUSD,D1)   XAGUSD  in: 18.43400 sl:18.43350  diff:0.00050  delta:5000.00000  delta:*diff:2.50000  tVal:0.05000  tSz:0.00001
2022.07.25 17:46:22.772 test_MM-functions (EURUSD,D1)   EURUSD  in: 1.02186 sl:1.02236  diff:0.00050  delta:100000.00000  delta:*diff:50.00000  tVal:1.00000  tSz:0.00001
2022.07.25 17:46:22.773 test_MM-functions (EURUSD,D1)   Set: Risk: 5.0 %, dSL: 50  Com/Lot: 2.00  Free: 5348.69 USD:  XAUUSD  SE  in: 1717.10000  sl: 1717.15000  lotsC: 38.2000 (-191.00)  lotsB: 53.4900 (-267.45)
2022.07.25 17:46:22.773 test_MM-functions (EURUSD,D1)   Set: Risk: 5.0 %, dSL: 50  Com/Lot: 2.00  Free: 5348.69 USD:  XAGUSD  BU  in: 18.43400  sl: 18.43350  lotsC: 59.4300 (-148.57)  lotsB: 106.9700 (-267.42)
2022.07.25 17:46:22.773 test_MM-functions (EURUSD,D1)   Set: Risk: 5.0 %, dSL: 50  Com/Lot: 2.00  Free: 5348.69 USD:  EURUSD  SE  in: 1.02186  sl: 1.02236  lotsC: 5.1400 (-257.00)  lotsB: 5.3500 (-267.50)

在MQ账户上,手数会过多。

这是我比较两种方法的脚本:

//+------------------------------------------------------------------+
//|                                            test_MM-functions.mq5 |
//|                                                            Calli |
//|                              https://www.mql5.com/de/users/gooly |
//+------------------------------------------------------------------+
#property copyright "Calli"
#property link      "https://www.mql5.com/de/users/gooly"
#property version   "1.00"
#property script_show_inputs
//--- input parameters
input double   risk_perCent   = 5.0;   // risk of capital in % on free_margin
input double   diff_sl        = 50;    // diff sl in points from entry
input double   CommPerLot     = 2.00;  

string Com = "",Syms[] = {"XAUUSD", "XAGUSD", "EURUSD" }; //,"AUDUSD","GBPCHF","GBPUSD", "EURCAD", "USDCAD", "USDRUB", "GBPJPY", "USDJPY"};

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
#define  forEach(TYPE, VAR, ARRAY) \
                TYPE VAR=NULL; \
                for(int i##VAR=0;  i##VAR<ArraySize(ARRAY)&&((VAR=ARRAY[i##VAR])!=NULL||true);  i##VAR++)

void OnStart()
  {
//---
   MqlTick mqTick;
   forEach(string, sym, Syms){
      
      double pnt = SymbolInfoDouble(sym,SYMBOL_POINT);
      ENUM_ORDER_TYPE ord = GetMicrosecondCount()%2==0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; // randomly buy or sell
      SymbolInfoTick(sym,mqTick); 
      double entry = (ord==ORDER_TYPE_BUY) ? mqTick.ask : mqTick.bid,
             sl    = (ord==ORDER_TYPE_BUY) ? entry - diff_sl*pnt : entry + diff_sl*pnt,
             lossC = 0.0, lossB = 0.0,
             lotsC = lotszC(risk_perCent, entry, sl, sym, CommPerLot), 
             lotsB = lotszB(risk_perCent, entry, sl, sym, CommPerLot);
      
      if (!OrderCalcProfit(ord, sym, lotsC, entry, sl, lossC) ) 
         Print("chk OrderCalcProfit(",EnumToString(ord),", ",sym,", lot: ",lotsC,", in: ",DoubleToString(entry,6),", out: ",DoubleToString(sl,6),", lossC) => err: ",_LastError," lossC: ",lossC);
             
      if (!OrderCalcProfit(ord, sym, lotsB, entry, sl, lossB) ) 
         Print("chk OrderCalcProfit(",EnumToString(ord),", ",sym,", lot: ",lotsC,", in: ",DoubleToString(entry,6),", out: ",DoubleToString(sl,6),", lossC) => err: ",_LastError," lossC: ",lossC);
             
      string res = StringFormat("Set: Risk: %.1f %%, dSL: %.0f  Com/Lot: %.2f  Free: %.2f %s:  %s  %s  in: %.5f  sl: %.5f  lotsC: %.4f (%+.2f)  lotsB: %.4f (%+.2f)",
                                 risk_perCent, diff_sl, CommPerLot,
                                 AccountInfoDouble(ACCOUNT_MARGIN_FREE),AccountInfoString(ACCOUNT_CURRENCY),
                                 sym, (ord==ORDER_TYPE_BUY ? "BU" : "SE"), entry, sl, lotsC, lossC, lotsB, lossB );
      Com = Com + res+"\n";
   }
   Comment(Com);
   //Print(Com);
  }
//+------------------------------------------------------------------+
double lotszC (double risk, double entry, double sl, string sym="", double CommissionPerLot=0) {
   if (sym == "") sym = _Symbol;
   double deltaValue = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE) / SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
   ENUM_ORDER_TYPE ordDir = entry > sl ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   double diff = fabs (entry - sl); 
   Print(sym,"  in: ",DoubleToString(entry,5)," sl:",DoubleToString(sl,5),"  diff:",DoubleToString(diff,5),
         "  delta:",DoubleToString(deltaValue,5),"  delta:*diff:",DoubleToString(deltaValue*diff,5),
         "  tVal:",DoubleToString(SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE),5),"  tSz:",
         DoubleToString(SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE),5));
   double lts = ( (AccountInfoDouble(ACCOUNT_MARGIN_FREE) * risk/100) / (diff * deltaValue + CommissionPerLot) );
   lts = ( fmin(fmax(SymbolInfoDouble(sym,SYMBOL_VOLUME_MIN),lts),SymbolInfoDouble(sym,SYMBOL_VOLUME_MAX)));
   double stepSize = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
   return (MathRound(lts/stepSize)*stepSize);
}

double lotszB (double risk, double entry, double sl, string sym="", double CommissionPerLot=0) {
   if (sym == "") sym = _Symbol;
   ENUM_ORDER_TYPE ordDir = entry > sl ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   double loss;
   if (!OrderCalcProfit(ordDir, sym, 1, entry, sl, loss)) return(-1.0);
   double lts = ((AccountInfoDouble(ACCOUNT_MARGIN_FREE) * risk * 0.01) / -loss);
   lts = (fmin(fmax(SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN), lts), SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX)));
   double stepSize = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
   return (MathRound(lts / stepSize) * stepSize);
}

我将方向定为 in > sl(买入)或 in < sl(卖出)。这样挂单就没有问题了

 

感谢您的测试。是的,如果您将结果相互比较,一方面可以看到OrderCalcProfit 的一致性,另一方面,至少对 EURUSD 和 RoboForex 而言,结果大约相差 "手数 * 每手佣金"。这一点可以补充:

if (!OrderCalcProfit(ordDir, sym, 1, entry, sl, loss)) return(-1.0);
double lts = ((AccountInfoDouble(ACCOUNT_MARGIN_FREE) * risk * 0.01) / (-loss + CommissionPerLot);
如果我正确使用论坛搜索,有没有办法使用 MQL5 直接查询 "CommissionPerLot "值?
 
Benjamin Fotteler #:


如果我正确使用了论坛搜索,那么没有办法直接使用 MQL5 查询 "CommissionPerLot "值,对吗?

是的,不能直接在终端中查询,但可以向经纪人或在交易历史中查询:DEAL_COMMISSION

Dokumentation zu MQL5: Konstanten, Enumerationen und Strukturen / Handelskonstanten / Eigenschaften der Deals
Dokumentation zu MQL5: Konstanten, Enumerationen und Strukturen / Handelskonstanten / Eigenschaften der Deals
  • www.mql5.com
Eigenschaften der Deals - Handelskonstanten - Konstanten, Enumerationen und Strukturen - Nachschlagewerk MQL5 - Nachschlagewerk über die Sprache des algothitmischen/automatischen Handels für MetaTrader 5