需要基于SL和账户风险的资金管理LOT大小公式! - 页 3

 

好了,伙计们!这段代码是我写的,是我在自己的EA中使用的。它相当复杂,因为除了风险%和止损外,它还考虑到了保证金风险%,以及根据最小、最大和步骤大小来修正手数。它还总是使用当前余额和净值的最小值,而不是只使用其中之一。我觉得这种方式更安全。

然而,请注意,它在计算中不使用点差,因为我在计算要使用的止损时单独计算。因此,下面的函数使用了一个相对的止损 大小。在我的EA中,参数dblStopLossPips 是事先计算好的,取决于各种因素,如策略、点差、ATR等;所以传递给dblLotsRisk() 函数的最终值已经是一个最终值,以便计算出要使用的手数大小。

// Function to Determine Tick Point Value in Account Currency

        double dblTickValue( string strSymbol )
        {
                return( MarketInfo( strSymbol, MODE_TICKVALUE ) );
        }
        

// Function to Determine Pip Point Value in Account Currency

        double dblPipValue( string strSymbol )
        {
                double dblCalcPipValue = dblTickValue( strSymbol );
                switch ( MarketInfo( strSymbol, MODE_DIGITS ) )
                {
                        case 3:
                        case 5:
                                dblCalcPipValue *= 10;
                                break;
                }
                
                return( dblCalcPipValue );
        }
        

// Calculate Lot Size based on Maximum Risk & Margin

        double dblLotsRisk( string strSymbol, double dblStopLossPips,
                double dblRiskMaxPercent, double dblMarginMaxPercent,
                double dblLotsMin, double dblLotsMax, double dblLotsStep )
        {
                double
                        dblValueAccount = MathMin( AccountEquity(), AccountBalance() )
                ,       dblValueRisk    = dblValueAccount * dblRiskMaxPercent / 100.0
                ,       dblValueMargin  = AccountFreeMargin() * dblMarginMaxPercent / 100.0
                ,       dblLossOrder    = dblStopLossPips * dblPipValue( strSymbol )
                ,       dblMarginOrder  = MarketInfo( strSymbol, MODE_MARGINREQUIRED )
                ,       dblCalcLotMin
                                = MathMax( dblLotsMin, MarketInfo( strSymbol, MODE_MINLOT ) )
                ,       dblCalcLotMax
                                = MathMin( dblLotsMax, MarketInfo( strSymbol, MODE_MAXLOT ) )
                ,       dblModeLotStep  = MarketInfo( strSymbol, MODE_LOTSTEP )
                ,       dblCalcLotStep  = MathCeil( dblLotsStep / dblModeLotStep ) * dblModeLotStep
                ,       dblCalcLotLoss
                                = MathFloor( dblValueRisk / dblLossOrder / dblCalcLotStep ) * dblCalcLotStep
                ,       dblCalcLotMargin
                                = MathFloor( dblValueMargin / dblMarginOrder / dblCalcLotStep ) * dblCalcLotStep
                ,       dblCalcLot = MathMin( dblCalcLotLoss, dblCalcLotMargin )
                ;
                
                if ( dblCalcLot < dblCalcLotMin ) dblCalcLot = dblCalcLotMin;
                if ( dblCalcLot > dblCalcLotMax ) dblCalcLot = dblCalcLotMax;

                return ( dblCalcLot );
        }
 
GumRai:

这让我感到头疼的是,我只是想弄清楚括号里的内容。

说实话,我完全不知道你在这里试图实现什么。

我看不出MODE_STOPLEVEL或SPREAD有什么关系,你肯定应该以当前价格的止损距离为基础进行计算?

账户货币是什么应该没有区别,计算应该是一样的,因为TICKVALUE是账户货币。

请注意,把你的代码行放在两行上,帖子就不会那么宽了,不需要左右滚动就能读懂:)

我在前几页贴了一张图片,其中说明了我的公式是如何计算手数的。但pipvalue或tickvalue或其他什么总是乱七八糟的。Quote->base currency 和其他令人困惑的东西,但到目前为止我的公式做得很好,尽管我不确定它是否正确。

SPREAD可能无关紧要,但止损水平是必要的。我把SL放在最接近订单开价的位置,这就是止损水平,但由于波动和峰值,我有时需要手动调整,这就是为什么我放了一个STOPSLIP变量,我可以根据波动性或其他情况调整SL。

FMIC

好了,伙计们!这段代码是我写的,是我在自己的EA中使用的。 它相当复杂,因为除了风险%和止损,它还考虑到了保证金风险%,以及基于最小、最大和步骤大小的手数校正。它还总是使用当前余额和净值的最小值,而不是只使用其中之一。我觉得这种方式更安全。

但是,请注意,它在计算中不使用点差,因为我在计算要使用的止损时单独计算。因此,下面的函数使用了一个相对的止损大小。在我的EA中,参数dblStopLossPips 是事先计算好的,取决于各种因素,如策略、点差、ATR等;所以传递给dblLotsRisk() 函数的最终值已经是一个最终值,以便计算出要使用的手数大小。

谢谢,我将测试它并告诉我的反馈意见

虽然我不明白你为什么把这么多的变量放在那里,整个代码可以装在一行里:)

 
Proximus:

我在前几页贴了一张图片,其中说明了我的公式是如何计算手数的。但pipvalue或tickvalue或其他什么总是乱七八糟的。Quote->base currency和其他令人困惑的东西,但到目前为止我的公式做得很好,尽管我不确定它是否正确。

SPREAD可能无关紧要,但止损水平是必要的。我把SL放在最接近订单开盘价的位置,这就是止损水平,但由于波动和峰值,我有时需要手动调整,这就是为什么我放了一个STOPSLIP变量,我可以根据波动性或其他情况调整SL。

谢谢,我将测试它并告诉我的反馈!

虽然我不明白你为什么把这么多的变量放在那里,整个代码可以装在一行里:)


是的,代码可以全部放在一行中,但相信我,这绝不是一个好的编码方式,除非你试图从你的代码中挤出每一个CPU周期,成为地球上最快的。

这就是为什么"GumRai " 抱怨说他对其他代码感到头疼。它根本不具有可读性,也不容易理解,这使得它很难调试。

我的方法可能更啰嗦,但它更容易调试和维护,也更易读,更容易被其他人(如你)理解。

但你可以自由地把它压缩成一行。如果它不能提供相同的结果,请不要抱怨。我会把它留给你来调试的。

 

很抱歉重开这个话题,但是确认一些事情是很重要的,所以这是我想出来的函数(我把它公开了,你以后可以感谢我)。

double LOTUNITSTORISK()
{
double LOTS=((AccountBalance()*RISKPERCENT/100) / (  MarketInfo(Symbol(), MODE_TICKVALUE)*MarketInfo(Symbol(), MODE_TICKSIZE)*STOPSIZE     ));
return LOTS;
}


这个函数应该返回基于账户风险的手数单位,并通过欧元账户计算,因为欧元始终是基础货币。

手数单位的意思是=头寸的实际资金规模,所以对于一个100欧元的账户,1%的风险,应该返回1欧元,根据STOPLOSS,例如,100吸管的止损应该是1000手单位(MT4的0.01手)。

关键是账户货币 是欧元,没有其他。

一旦我们调用LOTUNITTORISK(),我们将把结果除以100.000,得到MT4格式的实际手数(1000现金单位在MT4中为0.01手)。

RISKPERCENT=是一个int ,它可以是1,2,3,4,我们的风险%。

STOPSIZE= 是一个int ,它是我们的止损大小的点数(5位数经纪商的点数/10),所以例如60点SL是一个6点SL。

我想知道这个函数是否能正确计算手数,请测试一下,如果你发现任何错误,请帮助我:)

千恩万谢!

 
Proximus:
MarketInfo(Symbol(), MODE_TICKVALUE)* MarketInfo(Symbol(), MODE_TICKSIZE)*STOPSIZE

Risk  = lotsize * StopSize * TickValue /  TickSize
         1      *  0.0100  *  $10.00   / 0.0001
$1000 = one lot * 100 pips *  $10.00   / pip
  1. 你把止损放在它需要的地方--交易的理由不再有效的地方。例如,交易一个支撑位的反弹,止损要低于支撑位。
  2. 帐户余额*百分比=RISK=(OrderOpenPrice-OrderStopLoss)*DIR*OrderLots*DeltaPerlot(注意OOP-OSL包括SPREAD)。
  3. 不要使用TickValue本身 -DeltaPerlot
  4. 你还必须检查FreeMargin以避免止损
 
WHRoeder:
  1. 你把止损放在它需要的地方--交易的理由不再有效的地方。例如,交易一个支撑位的反弹,止损要低于支撑位。
  2. 帐户余额*百分比=RISK=(OrderOpenPrice-OrderStopLoss)*DIR*OrderLots*DeltaPerlot(注意OOP-OSL包括SPREAD)。
  3. 不要单独使用TickValue -DeltaPerlot
  4. 你还必须检查FreeMargin以避免止损

1) 该函数只返回货币单位的LOT SIZE,而不是MT4单位,当我下单时,分别从Bid(买入)和Ask(卖出)中提取STOPSIZE,这就像MT4处理TP和SL一样。

买入在ASK开仓,在BID平仓

卖出在BID开仓,在ASK平仓。

2) 我不能使用OrderOpenprice man,因为在这个函数计算之前,没有订单被打开。不包括点差,点差将在订单打开后我添加/抽象STOPSIZE时被处理。

但在此之前,我们需要确定手数,这是合乎逻辑的。

3) 我不明白这一点。

4) 很明显,但我再次强调,下单功能是在这之后运行的,与此功能关系不大。这个函数的唯一目的是确定手数,没有别的。


TickValue /  TickSize

不正确,如果我除以它们,那么我得到错误的数字,也许对于美元账户应该这样做,但它是一个欧元账户。

 
Proximus:

买入以ASK开盘,以BID收盘 卖出以BID开盘,以ASK收盘

2) 我不能使用OrderOpenprice

3) 我不明白这一点。

4)T,如果我把它们相除,那么我得到了错误的数字,也许对于美元账户应该这样做,但它是一个欧元账户。它们必须相乘。

  1. 问价 买入时的订单开盘价
  2. Bid 卖出的OrderOpenPrice 。为什么你不能使用它,你必须知道它才能把它传给OrderSend?
  3. 你必须使用tickvalue/ticksize。Tickvalue本身是没有意义的。
  4. 你必须进行除法以获得正确的单位(价格变化)*(tickValue)/(价格变化)给你一个值。每点10美元=每点1美元=价值/变化。记住,结果是账户货币,所以当你用它除以你的风险时,你会得到很多纯数字,同样,单位取消$risk(BAL%)/$risk(SL)。如果你必须使用多头,那你就做错了,或者经纪人的价值被搞乱了。
 
WHRoeder:
普罗米修斯

买入在ASK开仓,在BID平仓 卖出在BID开仓,在ASK平仓

2) 我不能使用OrderOpenprice

3) 我不明白这一点。

4)如果我把它们相除,那么我得到的数字是错误的,也许对于美元账户应该这样做,但它是一个欧元账户,它们必须相乘。

  1. 问价 买入时的订单开盘价
  2. Bid 卖出的OrderOpenPrice 。为什么你不能使用它,你必须知道它才能把它传给OrderSend?
  3. 你必须使用tickvalue/ticksize。Tickvalue本身是没有意义的。
  4. 你必须进行除法以获得正确的单位(价格变化)*(tickValue)/(价格变化)给你一个值。每点10美元=每点1美元=价值/变化。记住,结果是账户货币,所以当你用它除以你的风险时,你会得到很多纯数字,同样,单位取消$risk(BAL%)/$risk(SL)。如果你必须要用多个单位,那么你就做错了,或者经纪人的价值被搞乱了。


1,2 我知道,但请理解我,这是由另一个函数处理的,与这个函数无关。

3) 据我所知,tickvalue是基础货币中1点的价值,所以根据我使用的货币对,它要么要除以它,要么要乘以它,在欧元账户的情况下,我们似乎要乘以而不是除以。

这里有一张图片可以更好地说明问题。


在欧元/美元上,3%的风险交易我们需要开1798个单位,在MT4单位中四舍五入0.02个LOTS来实现。

STOPLOSS的大小是由另一个函数决定的。

我测试了一下,似乎是正确的,但我不确定这个公式是否真的精确,这是我想确定的,所以请帮忙。

 

我也一直试图弄清楚这个基于SL、账户风险和追加保证金水平的手数计算,特别是当追加保证金水平不是100%而是120%时。我找到的最佳答案是WHRoeder 他的whrea.mq4 代码中分享的。whrea.mq4代码需要一些修正,但WHRoeder已经 他对RaptorUK 评论 的回答中给出了修正。因此,计算手数的完整答案是存在的,但要完全理解WHRoeder所分享的内容,还需要一些努力。

我附上了我从WHRoeder的whrea.mq4中提取和修改的代码,以便在最新的MT4版本中编译,计算保证金追加水平超过100%的多头交易的手数。

但是,我不确定乘以MarginCallLevel%是否正确,以避免追加保证金水平%为考虑因素。如果MarginCallLevel是100%,那么这两行代码都是正确的,但如果MarginCallLevel是120%,乘以MarginCallLevel%是否是一个正确的追加保证金测试?如果不是,那么正确的方法是什么?WHRoeder,你能帮助解决这个问题吗?威廉,我已经尽力了。

以下是该保证金测试部分的代码,用于多头交易。

extern double MarginCallLevel = 120; //As a percentage

double MarginCallLevel1 = MarginCallLevel * 0.01; 

        double  AFMC    = AccountFreeMarginCheck(Symbol(), OP_BUY, tradesize),
                        eRisk   = equityatrisk + atrisknew;

        //Test for margin
        //Note: Not sure if multiplying by the MarginCallLevel % here is correct to 
        //take the Margin Call Level % into account for avoiding a margin call.
        //If the MarginCallLevel is 100% then both lines of code would be correct
        //but if the MarginCallLevel is 120% would multiplying by the MarginCallLevel %
        //be a correct Margin Call test? If not, then what is the correct way to do this?

        //if (AFMC*0.99 <= eRisk){
        if (AFMC*0.99 <= eRisk*MarginCallLevel1){
            tradesize *= 0.95;    // Must still round to lotStep.
            continue;   }   // Prevent margin call if new trade goes against us.
附加的文件:
 

...在这部分代码中,有一个新的编译问题(错误--->'MarketInfo'---非法切换表达式类型),也许在更新到MT4 build 600+之前都是正常的...但从那时起它就不再工作了。

// Function to Determine Pip Point Value in Account Currency

        double dblPipValue( string strSymbol )
        {
                double dblCalcPipValue = dblTickValue( strSymbol );
                switch ( MarketInfo( strSymbol, MODE_DIGITS ) )
                {
                        case 3:
                        case 5:
                                dblCalcPipValue *= 10;
                                break;
                }
                
                return( dblCalcPipValue );
        }
        

所以,你能不能发布一些更新的版本......当然,如果你还在的话。