今天的文章为中级 MQL5 编程人员讲解如何通过轻松实施所谓的幂的技术从他们的线性交易系统(固定手数)中获利更多。本文中使用的泛称取幂是指那些使市场中下达的仓位的规模或数量与其风险相适应的货币管理模型。这是因为结果资产净值曲线呈抛物线形式,以几何级数或指数增长。术语“线性”也用于本文的上下文中,是一个介于数学和编程之间的术语。具体而言,我们将实施一个由 Ralph Vince 开发的固定分数仓位大小的实际 MQL5 变体。
图 1. 数学抛物线
现在,让我们快速回顾一下资金管理模型,看看我们可以如何实现 Ralph Vince 的固定分数仓位规模的变体。准备好了吗?不要错过从您的交易策略获利更多的机会!
本资金管理模型背后的理念是根据与操作相关的估计风险对操作进行分级。风险是每项交易净额的相同部分。
固定分数仓位规模中合约数量的方程如下:
N = f * Equity / Trade Risk
N 是合约数量,f 是固定分数(介于 0 和 1 之间的数),Equity 是账户资产净值的当前值,Trade Risk 是计算合约数量的每份合约的风险。请阅读 Michael R. Bryant 的《固定分数仓位规模》一文,以更深入地了解此模型。
固定分数模型的一个有趣属性是,由于操作的规模保持与账户的净余额成比例,从理论上说不可能损失所有的资金。破产的风险为零。从另一方面来说,由于风险资金的百分比较低,连赢或连输操作不会对利润曲线造成显著影响。
当然,首先您需要一个线性交易系统以体验低风险指数幂!可以这么说,这个系统将作为幂底。但我所指的线性系统是经证明在某个时间区间内是赢家且其资产净值曲线看上去像一条直线的交易系统。例如,HawaiianTsunamiSurfer 就是代码库中提供的所谓的线性交易系统。其资产净值曲线在从 2012 年 1 月到 2012 年 3 月的时间区间内看起来像一条直线。
图 2. HawaiianTsunamiSurfer 从 2012 年 1 月到 2012 年 3 月的资产净值曲线
本文的目的不是从头开发一个线性交易系统,而是为您提供必要的工具,以便您可以从您的系统中获益更多。所以从现在开始,我假设您已经在面向对象范式下开发了一个类似于这个系统的交易系统。在这种情况下,您应添加我在下文中说明的面向对象块。
所以,我们再次采取面向对象的方法来编写我们的 EA 的代码。我建议您首先阅读《另一个 MQL5 OOP 类》和《建立自动新闻交易者》这两篇文章,获得以此面向对象的方式工作的技术基础。如果您已经完成这一步,记住在那些文章中讨论的设计包含了名为 CEvolution 的非常重要的元素。这允许我们对一些重要的临时信息保持追踪,例如自动交易在给定时刻的状态、执行的操作的历史数据等。
这一次,我们将在 CEvolution 中编写管理我们的资金所需的逻辑的代码。由于风险固定分数与资产净值保持比例,在此我们都同意它不是恒定的而是可变的,此逻辑必须在 CEvolution 中编写代码。或者简单地说,由于资产净值曲线的斜率随时间而变化,所有这些问题必须在 CEvolution 中实现。这是我们面向对象设计的抽象概念。将下列面向对象类与您的面向对象风格的交易系统集成起来的工作留给读者作为练习。
类 CEvolution.mqh:
//+------------------------------------------------------------------+ //| CEvolution.mqh | //| Copyright © 2013, Jordi Bassagañas | //+------------------------------------------------------------------+ #include <Mine\Enums.mqh> //+------------------------------------------------------------------+ //| CEvolution Class | //+------------------------------------------------------------------+ class CEvolution { protected: ENUM_STATUS_EA m_status; // The current EA's status ENUM_EXP_EQUITY_CURVE_LEVEL m_expEquityLevel; // The current exponential equity level double m_originalEquity; // The original equity value double m_lotSize; // The current lot size public: //--- Constructor and destructor methods CEvolution(ENUM_STATUS_EA status,ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level); ~CEvolution(void); //--- Getter methods ENUM_STATUS_EA GetStatus(void); ENUM_EXP_EQUITY_CURVE_LEVEL GetExpEquityLevel(void); double GetOriginalEquity(void); double GetLotSize(void); //--- Setter methods void SetStatus(ENUM_STATUS_EA status); void SetExpEquityLevel(ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level); void SetOriginalEquity(double equity); void SetLotSize(double size); //--- CEvolution specific methods double CalcEquityGrowth(double currentEquity); void RefreshExpEquityLevel(double currentEquity); void RefreshLotSize(); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CEvolution::CEvolution(ENUM_STATUS_EA status,ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level) { m_status=status; m_expEquityLevel=exp_equity_level; RefreshLotSize(); m_originalEquity=AccountInfoDouble(ACCOUNT_EQUITY); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CEvolution::~CEvolution(void) { } //+------------------------------------------------------------------+ //| GetStatus | //+------------------------------------------------------------------+ ENUM_STATUS_EA CEvolution::GetStatus(void) { return m_status; } //+------------------------------------------------------------------+ //| GetExpEquityLevel | //+------------------------------------------------------------------+ ENUM_EXP_EQUITY_CURVE_LEVEL CEvolution::GetExpEquityLevel(void) { return m_expEquityLevel; } //+------------------------------------------------------------------+ //| GetEquity | //+------------------------------------------------------------------+ double CEvolution::GetOriginalEquity(void) { return m_originalEquity; } //+------------------------------------------------------------------+ //| GetLotSize | //+------------------------------------------------------------------+ double CEvolution::GetLotSize(void) { return m_lotSize; } //+------------------------------------------------------------------+ //| SetStatus | //+------------------------------------------------------------------+ void CEvolution::SetStatus(ENUM_STATUS_EA status) { m_status=status; } //+------------------------------------------------------------------+ //| SetExpEquityLevel | //+------------------------------------------------------------------+ void CEvolution::SetExpEquityLevel(ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level) { m_expEquityLevel=exp_equity_level; } //+------------------------------------------------------------------+ //| SetEquity | //+------------------------------------------------------------------+ void CEvolution::SetOriginalEquity(double equity) { m_originalEquity=equity; } //+------------------------------------------------------------------+ //| SetLotSize | //+------------------------------------------------------------------+ void CEvolution::SetLotSize(double lot_size) { m_lotSize=lot_size; } //+------------------------------------------------------------------+ //| CalcEquityGrowth | //+------------------------------------------------------------------+ double CEvolution::CalcEquityGrowth(double currentEquity) { return NormalizeDouble(currentEquity * 100 / m_originalEquity - 100,2); } //+------------------------------------------------------------------+ //| RefreshExpEquityLevel | //+------------------------------------------------------------------+ void CEvolution::RefreshExpEquityLevel(double currentEquity) { double growth = CalcEquityGrowth(currentEquity); //--- is the current equity less than 10% of the original amount? if(growth <= 10) { SetExpEquityLevel(LEVEL_ONE); } //--- is the current equity more than 10% of the original amount and less than 20%? else if(growth > 10 && growth <= 20) { SetExpEquityLevel(LEVEL_TWO); } //--- is the current equity more than 20% of the original amount and less than 30%? else if(growth > 20 && growth <= 30) { SetExpEquityLevel(LEVEL_THREE); } //--- is the current equity more than 30% of the original amount and less than 40%? else if(growth > 30 && growth <= 40) { SetExpEquityLevel(LEVEL_FOUR); } //--- is the current equity more than 40% of the original amount and less than 50%? else if(growth > 40 && growth <= 50) { SetExpEquityLevel(LEVEL_FIVE); } //--- is the current equity more than 50% of the original amount and less than 60%? else if(growth > 50 && growth <= 60) { SetExpEquityLevel(LEVEL_SEVEN); } //--- is the current equity more than 60% of the original amount and less than 70%? else if(growth > 60 && growth <= 70) { SetExpEquityLevel(LEVEL_EIGHT); } //--- is the current equity more than 70% of the original amount and less than 80%? else if(growth > 70 && growth <= 80) { SetExpEquityLevel(LEVEL_NINE); } //--- is the current equity more than 90% of the original amount? else if(growth > 90) { SetExpEquityLevel(LEVEL_TEN); } } //+------------------------------------------------------------------+ //| RefreshLotSize | //+------------------------------------------------------------------+ void CEvolution::RefreshLotSize() { switch(m_expEquityLevel) { case LEVEL_ONE: SetLotSize(0.01); break; case LEVEL_TWO: SetLotSize(0.02); break; case LEVEL_THREE: SetLotSize(0.03); break; case LEVEL_FOUR: SetLotSize(0.04); break; case LEVEL_FIVE: SetLotSize(0.05); break; case LEVEL_SIX: SetLotSize(0.06); break; case LEVEL_SEVEN: SetLotSize(0.07); break; case LEVEL_EIGHT: SetLotSize(0.08); break; case LEVEL_NINE: SetLotSize(0.09); break; case LEVEL_TEN: SetLotSize(0.1); break; } } //+------------------------------------------------------------------+
现在,让我们对这个类的一些重要部分进行注释!
当创建“EA 交易”时,原始资产净值曲线的值存储在 m_originalEquity 中:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CEvolution::CEvolution(ENUM_STATUS_EA status,ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level) { m_status=status; m_expEquityLevel=exp_equity_level; RefreshLotSize(); m_originalEquity=AccountInfoDouble(ACCOUNT_EQUITY); }
方法 CEvolution::CalcEquityGrowth 用于计算资产净值曲线的增长,这始终是相对于其原始值而言:
//+------------------------------------------------------------------+ //| CalcEquityGrowth | //+------------------------------------------------------------------+ double CEvolution::CalcEquityGrowth(double currentEquity) { return NormalizeDouble(currentEquity * 100 / m_originalEquity - 100,2); }
最后,CEvolution::RefreshExpEquityLevel 用于刷新每一价格变动的资产净值水平(观察它是如何完全取决于资产净值增长的),CEvolution::RefreshLotSize 用于刷新每一价格变动的手数。这是因为您应该以下列方式在您的 EA 的 OnTick 方法中刷新该信息:
GetEvolution().RefreshExpEquityLevel(AccountInfoDouble(ACCOUNT_EQUITY)); GetEvolution().RefreshLotSize();
顺便提一下,此解决方案要求使用下列自定义 MQL5 枚举:
//+------------------------------------------------------------------+ //| Exponential equity curve level enumeration | //+------------------------------------------------------------------+ enum ENUM_EXP_EQUITY_CURVE_LEVEL { LEVEL_ONE, LEVEL_TWO, LEVEL_THREE, LEVEL_FOUR, LEVEL_FIVE, LEVEL_SIX, LEVEL_SEVEN, LEVEL_EIGHT, LEVEL_NINE, LEVEL_TEN };我们说这个实现是固定分数的变体,是因为它的确引进了一些特异性。例如,资产净值曲线在达到所谓的水平十之前将呈指数增长,之后系统变成线性。然而,CEvolution 保留了恒定与资产净值曲线成比例增大仓位规模的基本理念。
综上所述,您已经可以根据您的自动交易的当前状态作出资金管理决策。
在您的 EA 的 OnTick 方法中:
switch(GetEvolution().GetStatus()) { case BUY: tp = ask + m_takeProfit * _Point; sl = bid - m_stopLoss * _Point; GetTrade().PositionOpen(GetBrain().GetSymbol(),ORDER_TYPE_BUY,m_evolution.GetLotSize(),ask,sl,tp); break; case SELL: sl = ask + m_takeProfit * _Point; tp = bid - m_stopLoss * _Point; GetTrade().PositionOpen(GetBrain().GetSymbol(),ORDER_TYPE_SELL,m_evolution.GetLotSize(),bid,sl,tp); break; case DO_NOTHING: // Nothing... break; }
我将新的指数化系统重命名为 ExponentialHawaiian。
完成上文中说明的面向对象逻辑的添加后,不要忘记对您的系统运行测试!现在我来回测 ExponentialHawaiian - HawaiianTsunamiSurfer 的固定分数变体:
图 3. ExponentialHawaiian 从 2012 年 1 月到 2012 年 3 月的资产净值曲线
上面的曲线将保持指数化,而下面的系统保持线性。当这个条件不再为真时,系统变得不稳定,从理论上存在破产的风险。
今天我们学习了如何通过将我们实施固定手数资金管理模型的线性系统升级至幂系统来获得更多利润。
首先我们展示了几个经典的资金管理模型(固定手数、固定分数、固定比率、Kelly 的百分比、实际成本)并决定专注于固定分数 - 一个操作规模保持与账户净余额成比例的简单模型。最后,我们采取了在一段时间内显示线性结果的交易系统,我们以 MQL5 实施了固定分数的变体,并显示了 MetaTrader 的策略测试程序启动的结果。
我们再次使用面向对象方法编写我们的“EA 交易”。我强烈建议您首先阅读《另一个 MQL5 OOP 类》和《建立自动新闻交易者》这两篇文章,获得以此面向对象的方式工作的技术基础。
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程