目录
- 什么是金融市场的过程动态?
- 在金融市场上获利的概率是多少?
- 与价格变动动态相关的市场风险
- 与市场动态相关的风险分类
- 入场交易时高波动性相关的风险
- 入场交易时存在阻力水平相关的风险
- 入场交易时在超买/超卖区域结束相关的风险
- 入场交易时没有明确趋势相关的风险
- 选择指标计算周期数相关的风险
- 入场交易时使用挂单相关的风险
- 入场交易之后价格变化幅度不确定性相关的风险
- 入场交易之后价格剧变相关的风险
- 在分析中只使用一种价格变化尺度相关的风险
- 只使用技术分析或者基本分析相关的风险
- 不与市场动态相关的风险
- 与市场动态无关的风险的分类
- 交易系统结构相关的风险
- 超过亏损限额(管理投资者存款风险限额)相关的风险
- 交易条件有负面变化相关的风险
- 由经纪商服务器连接质量决定的风险
- 经纪商与客户方面对自动交易许可相关的风险
- 与金融市场法规改变相关的风险
- 一个用于降低一些上述风险的简单EA交易模块
- 结论
简介
首先,这篇文章将对交易和分析新手在开发他们自己的交易策略时会有所帮助。然而,就算经验丰富的市场参与者也可能会找到有用的内容,例如风险的分类,把烛形分析应用到定义超买/超卖区域中去,基本分析和技术分析的关系,选择移动平均计算的周期数,以及降低与可能的价格剧变有关的风险。
本文处理了下面的问题:
- 在金融和股票市场中交易过程动态的本质;
- 交易中的获利概率;
- 当开发交易系统时降低交易者风险的方法。
我并不是承诺这是在金融市场上进行交易的完整可靠的风险分析和分类,我们将会注重于和金融资产价格变化动态相关的主要市场风险。此外,我们将对与市场动态不直接相关但对交易效率仍然很重要的风险有所了解。写这篇文章时,我利用了我在分析和开发交易系统过程中积累的经验。
EA 交易的 MQL5 版本可以在这里找到。
什么是金融市场的过程动态?
当开发交易策略时(包括人工交易和自动化交易), 我们应当了解我们所处理的过程。金融市场的价格变化是一个不稳定的过程,它会被多种因素所影响,并且常常无法确定哪一个是决定因素。
这个过程不稳定的特点是由市场参与者的行为决定的,他们的反应是多方面的。因此,市场的振幅和频率的变化不能由确定性的行为法则来决定。一般来说,这种过程可以被认为是随机的。
尽管在有些区域之内您还可以正确预测变化的方向。让我们列出可能使这些区域出现的因素。
- 波浪式的价格变化。我们可以定义波浪的开始:例如,烛形穿过一组移动平均线或来自常规指标的信号。我们现在还是不讨论这种定义的准确度,在此我们只是注意这是可能的。
- 狭窄的盘整区 (价格总是会离开它们的)。
- 一些用于反应某些基础、基本分析和技术分析的规则。
在金融市场上获利的概率是多少?
这是主要的问题,因为任何交易者实际也是投资者,金融市场交易中获利的概率直接关系到趋势延续预测的正确性,因为主运动范围正好位于趋势区域。
有很多方法用来计算趋势的延续或是反转,它们都有一个共同的缺点,因为任何交易系统都是市场状态模型。评估这样一个模型的准确性总是有问题的。首先,这个过程本身从动态的角度上是非常复杂的,因为它有非稳定(随机)的特点。其次,“随机过程”内部的所有精度评估方法也是复杂的,其效果是不明确的。
因此,为了评估获利的可能性,我们将以另一种方式使用实际的(而不是计算的)数据。要做到这一点,我们需要分析投资和经纪公司提供的外汇和股票市场交易效率的统计数据。
根据在文章 "在俄罗斯和美国个人交易外汇的成果" (俄语) 中提供的数据, 在2015年,在俄罗斯获利的个人交易者占 28%, 而在美国是占 33%。当然,这些数据不能被认为是详尽无遗的,因为这项研究只包含了有限数量的公司,研究期只有六个月。不管怎样,这些数字给我们提供了一些启示。可能的结论是什么呢?
大多数市场参与者使用的常规分析方法不允许我们有效地预测金融市场价格波动的过程。其他措施,包括资金管理方法,也效率低下。究其原因,主要是利用技术和基本分析对市场动态基本预测的初始效率低下。因此,只有不到三分之一的金融市场参与者获得利润。
而对于股票市场,统计结果是不一样的,我将引用相对“温和”的数据。根据法国金融市场局的研究,十个人中有八个人最终亏掉了他们的钱。这表明,在股票市场上交易的成果是 20%. 这比外汇市场更加糟糕,尽管其价值不好比较。.
正如我们所看到的,全面的风险核算对任何投资者来说都是至关重要的。
让我们重点关注两组主要的风险:
- 与价格变化动态相关的风险;
- 与市场动态无关的风险。
我们将会仔细研究这些风险,以及减少这些风险的方法。
我们将从第一组风险开始,它们的列表是由金融资产图表分析来决定的。我们需要分析图表的元素和它们的参数,包括单个烛形和它们的组的特性,以及移动平均线。我们不会使用其他常规指标,因为它们的数学模型不符合价格运动的概念,使它们效率低下。
与价格变动动态相关的市场风险
从技术上讲,主要的交易者风险是趋势的反转。金融资产的价格可能改变方向而走向开启仓位的相反方向,如果还没有开启仓位,风险就是预测这样的反转。
每个交易者都有他们自己对趋势的定义,虽然看起来很奇怪,但在技术分析中没有“官方”这个概念的定义,这意味着对趋势反转概率的评估也是主观的。每个交易者定义的临界振幅(趋势反转)取决于可接受风险(风险极限)。反过来,这个值是由每个交易者帐户上的资金金额来定义的。换句话说,一切都取决于最大可能的回撤。对银行好的因素对普通交易者可能就是坏的,
让我们看看风险的类型,再寻找方案来减少它们。
与市场动态相关的风险分类
传统的分析根据时间重点提出了三种类型的趋势:短期、中期和长期。
还经常提到局部和全局的趋势。通常情况下,局部的趋势是由短期或者中期趋势构成的,而全局趋势是由长期趋势构成的。没有明确定义的值来确定这些概念的时间和幅度边界,一切都是相对的。因此,让我们简化分析:反向变化的振幅将被用作趋势反转相关风险的标准。我们将根据重要的技术水平或取决于投资者存款的规模对其进行评估,并考虑到给定的风险限额。
为了将风险与趋势反转的可能性进行分类,还必须考虑到市场价格动态的因素。让我们简要地来检验它们。
- 入场交易时高波动性相关的风险。
- 入场交易时存在支撑水平相关的风险。
- 入场交易时在超买/超卖区域结束的风险。
- 入场交易时缺乏明确趋势相关的风险。
- 错误选择指标计算周期数相关的风险。
- 入场交易时使用挂单相关的风险。
- 在入场交易之后价格变化浮动不确定性相关的风险。
- 在入场交易之后价格剧变相关的风险。
- 只使用一个时段相关的风险。
- 只使用一种类型的分析(技术或基本分析)相关的风险。
入场交易时高波动性相关的风险
很多交易者完全没有考虑这类风险,这是一个很大的错误,因为在动荡加剧时,价格变化的幅度 (包括与主要趋势相反的方向) 都会增加,这就是风险因素。
使用传统的指标来评估波动性过于主观,首先,指标的设置本身是主观的,其次,他们的数学模型并不总是为这样的评估而设计的。因此,将盘整区域作为一种模型来定义市场进入时所需的波动程度是更为可靠的。
为了降低风险,我们可以在入场算法中设置以下的条件: 在最近的报价历史中的幅度限制阈值。可以设置这样的价格范围:
- 在两个反方向分形之间的幅度
- 或者一组烛形的幅度。
限制烛形的幅度是最简单的方法,让我们看一下相应的代码段:
//--- 入场交易算法 - 买入----------------------------------------------------------------------------------------- if( //----降低在入场交易时高波动性相关的风险 ---- //模拟在最近的历史中没有高的波动: ( High[1] - Low[1]) <= 200*Point && //在较低时段的烛形中限制幅度(tfМ1) ( High[2] - Low[2]) <= 200*Point && ( High[3] - Low[3]) <= 200*Point && (H_prev_m15 - L_prev_m15) <= 300*Point && //在较高时段烛形中限制幅度 (tfМ15) (H_2p_m15 - L_2p_m15) <= 300*Point && (H_3p_m15 - L_3p_m15) <= 300*Point && (H_prev_m15 - L_3p_m15) <= 300*Point && //在较高时段烛形中限制通道的幅度 (tfМ15) (High[1] - Low[1]) >= (1.1*(High[2] - Low[2])) && //限制在报价历史中相对于第二个柱之前的柱的活动 (High[1] - Low[1]) < (3.0*(High[2] - Low[2])) && //相同
图 1. 入场算法模块: 减少入场交易时高波动性相关的风险
图 1 展示了入场算法(买入)模块.
说明:
- High{1], High[2], High[3] — 在 M1 中前三个柱的 最高价 水平,
- H_prev_m15, H_2p_m15, H_3p_m15 — 在 M15 中前三个柱的最高价水平,
- Low[1], Low[2], Low[3] — 在 M1 中前三个柱的最低价水平,
- L_prev_m15, L_2p_m15, L_3p_m15 — 在 M15 中前三个柱的最低价水平。
这个模块可以让您在入场点位于较大波动区域的时候减少出现的风险。这是通过对水平价格通道以及在通道末端的活动(中等程度的波动)进行建模而得到的。
在 M1 和 M15 上的价格通道是使用限制在报价历史中前三个柱的烛形幅度来取得的,幅度的限制同时使用了单个烛形和整组烛形来做的,通道的幅度是根据它的第一个和最后一个烛形的极值的差距来定义的。
在通道末端的中等程度的波动性是通过限制在M1时段中两个临近烛形的幅度比例来模拟的(在这个例子中,使用的比例是从1.1到3.0)。当然,您可以使用其他的幅度比例。
问题时我们为什么要限制整个通道的幅度,限制每个烛形的幅度不是足够了吗?不,并非如此。如果我们不去定义整个通道的幅度,一个波浪式(而不是水平的)通道可能会被构建出来,而它的幅度可能是每个单个烛形大小的两倍。
这是用于买入的例子,对于卖出, 代码是一样的,因为通道和单个柱形的幅度都被定义为最高价和最低价之间的差别, 而方向是在另外的入场算法模块中设置的,而不是当前模块。
入场交易时存在阻力水平相关的风险
市场参与者对图表上的阻力水平有不同的反应。对一些人来说,这是利润目标,对其他人来说,是亏损限制器,对第三个部分来说,是水平突破的最初目标。就是为什么,分形级别经常被价格波动幅度不同的区域所包围。在这些区域的开放风险增加,而根据各种交易系统测试结果,它们内部的预测是无效的。所以,看起来把入场点放到趋势方向上的阻力水平之外是合理的。
我们应当怎样考虑这种交易风险呢?
如果仓位已经在阻力水平的方向上开启而价格正在接近它,就最好提前关闭这个仓位,因为有很高概率会出现强的回撤。
如果您准备根据您的算法来在价格突破了阻力水平之后来开启仓位,就应该等到在所选方向上出现可靠的突破。
实际上,这是一个真假突破的问题。一个可能的方案如下。等待直到在分形水平之后出现新的阻力水平,然后等待直到价格突破它。确保在较低的时段中使用,但是,这还是不够。当前的动态应当显示出明确信号,方向是突破的方向并且超过了新的分形水平。
这种方法的缺点是时段不确定。这是主观选择,因为不可能预先预测水平突破的幅度。因此,我们通过指定在入场时间之后通过水平的条件来简化这个问题,
当开发交易系统时,我们可以在入场条件中使用多个选项来减少出现阻力水平相关的风险。
- 选项 1. 在搜索最近的阻力分形之后 (在代码中,它是使用循环来实现的)。这种方法的优点是: 我们将会找到在这个时段中阻力的真实水平。但是,也有两个缺点,首先,对编程新手来说,开发循环可能有点困难,第二,分形在历史中可能会很深,也就是与阻力水平无关。
- 选项 2. 使用前一个烛形的最高价(用于买入)以及最低价(用于卖出)。这种方法有两个优点,首先,它的编程很容易,其次,您可以同时设置几个时段,就相当于搜索更早的分形。缺点是: 一些分形可能无法被侦测出来,因为烛形的极值只在有影线的时候才是分形。
对于编程新手,以及在开发人工交易时,我们推荐使用选项2: 它比较简单有效,尽管准确性会因为丢失一些分形而降低。这里是相应的代码段:
//----减少与入场交易时有阻力水平出现的风险----- //模拟当前价格超过局部支撑水平的情况: Bid > High[1] && //在 М1 (较低时段) Bid > H_prev_m15 && //在 М15 (较高时段)
图 2. 入场算法模块: 减少与入场交易时有阻力水平出现时的风险
图 2 显示了用于在入场算法中减少与入场时有阻力水平出现的风险, 买入入场。这是通过设置条件,认为当前价格已经在前一个柱的最高价穿过了阻力水平 (在两个时段中分开)。
我们应该另外设置变化的活动。然而,为了避免变量的重复,这必须在其他模块中完成 (同时设置方向和活动)。
如需建立卖出仓位, 要在下跌趋势中使用前一个柱形的最低价水平 (M1 和 M15 时段) 作为阻力水平。
入场交易时在超买/超卖区域结束相关的风险
这些风险包括,在波浪形运动的最后进入了市场,本来入场方向上的变化幅度较小,而反转的可能性大幅增加。这样的区域就是超卖/超买区域。使用传统的指标 (RSI 等等) 来定义它们通常是不够的,在很多情况下它们的信号是错的。原因是相同的: 传统的指标没有足够的数学算法来确定这些区域。为了更加准确地寻找超买/超卖区域,您需要识别出趋势变缓的迹象 (包括在 M1, 因为它会比其他时段上更快地显示出反转动态)。
我们将会通过根据下面的标准来综合分形和烛形分析,从而侦测趋势变缓的迹象:
- 相邻分形阻力水平之间的距离(幅度大小)变小,为了比较两个相邻区域的幅度,我们需要三个分形;
- 在一个烛形中增加修正,减小烛形的“烛体”(柱内分析);
- 改变烛形轴点相对于之前烛形轴点的偏移方向 (为此我们需要三个烛形).
如果使用了这个方法,就应当在入场算法条件中加上,上面列出的因素应该不存在。例如,这可以通过使用false(假) 和true(真)来做到, 其中true 的意思是指定的变缓因素在市场上出现。
然而,还有个更简单的选项。它与搜索超买/超卖区域不直接相关,这里使用的是一个间接的标记: 如果您在波浪形变化的开始进入市场,进入超买/超卖区域的可能性就大幅降低。实际上,我们是模拟了局部趋势的开始阶段。
- 首先,我们需要识别出一个或者多个移动平均(MA)在相同烛形内的交叉 - 这可能是波浪式运动的开端。为了确认波段的开始,我们需要另外的条件(参见下方),
- 然后再模拟波浪式运动的初始阶段,它将是新趋势的开始。为了取得这样的结果,我们指定: 在交叉后烛形的方向;它的活动;与前一柱交叉的快速移动平均的方向;当前价格与这些移动平均的相对位置。
注意: 当模拟局部趋势的初始阶段时,推荐只设置快速移动平均的方向。不需要设置快速移动平均的方向。
这种使用移动平均的方法如下: 更早的移动平均,因为它们有较大延迟,没有时间在新的趋势中反转方向。所以,如果我们设置了它们的方向,模拟的入场点可能距离趋势的起点很远,而落在危险的超买/超卖区域中。
第二个选项 (模拟局部趋势的初始阶段) 更加简单,所以推荐给编程新手。让我们看一下代码段:
//---减少与在超买区域内入场有关的风险----- //模拟绑定到波段的开端以减少进入超买区域的概率: ((MA8_prev > Low[1] && MA8_prev < High[1]) || (MA8_2p > Low[2] && MA8_2p < High[2]) || //波浪的开始 - 在数据历史中不超过三个柱(M1) (MA8_3p > Low[3] && MA8_3p < High[3])) && //相同 MA5_prev_m15 > L_prev_m15 && MA5_prev_m15 < H_prev_m15 && //波浪的开始 - 在更高时段的前一个柱 (М15)
图 3. 入场算法中的模块: 减少在入场交易时进入超买区域的风险
说明:
- МА8_prev, МА8_2p, МА8_3p — 在报价历史中(M1),使用周期数为8在前一个,第二个和第三个柱上计算所得的移动平均,
- МА5_prev_m15, МА5_2p_m15, МА5_3p_m15 — 在报价历史中(M15),使用周期数为5在前一个,第二个和第三个柱上计算所得的移动平均,
- 烛形的极值在之前设置 (参见图 2).
通过把入场点与估算的波形开端进行绑定,减少了进入超买区域的风险。波形开始的标记是,一个移动平均与柱形交叉: 在 М1, 这是一个周期数为8的 МА, 在 М15 上— 周期数为 5 的 МА。移动平均周期数值的选择是根据斐波那契序列原理的,我们将在“与不正确的指标计算周期数选择有关的风险”部分中更加详细地探讨这个参数。
这个模块不指定设置烛形和移动平均活动特征的参数,以及当前价格与移动平均相对的位置,这样做是为了不要重复的变量,我们将在“入场交易时缺少明确趋势有关的风险”模块中设置这些参数。
请注意,烛形与移动平均在M1时段中的交叉在历史中并不限于一个柱。它是通过逻辑或(OR)来设置的 - 在历史中或者在前一个柱,或者第二个,或者第三个柱上有交叉 (在 M1 中)。在 М15 中, 这种情况是要求有一个交叉选项 — 在报价历史中的前一个柱。这一系列潜在的选项使得可以考虑真实市场中局部趋势相对于这类交叉的多变情况。
上面的例子是用于买入入场的 (避免超买区域),对于卖出入场(避免超卖区域), 模块是一样的,因为移动平均与烛形交叉的算法并不依赖于移动的方向。
这样,我们已经探讨了两种方法来在入场交易时不会掉入超买/超卖区域,以及找到这些区域。您可以在创建您自己的交易系统或者开发交易指标时自己实验这些方法。
入场交易时没有明确趋势相关的风险
缺乏明确趋势是另一个不确定动态的因素和相关风险,我们会在市场由双边小幅振荡甚至平盘占据的时候讨论这一情景。
确定价格的方向很难,因为它一直在狭窄的范围内变化,所以,这在预测入场方向时出错的风险提高了。
这个问题甚至还更加复杂一些,因为传统的分析方法没有为我们提供平盘市场的明确定义(就和趋势的状况一样),所以,在平盘和趋势的开始之间没有边界定义。现有的方法非常主观: 平方差方法 (例如, 在StdDev 指标中), 以及更加高级的适应性函数方法 (例如, FRAMA). 这个问题在处理趋势定义的图形化方法时甚至更加复杂,根据不同的解释,各种市场阶段 (包括那些有明显振荡幅度的) 都被认为是平盘。这会导致亏损。
根据我个人的经验 (由交易系统的结果确认), 最有效的用来定义平盘边界的方法是在双边振荡趋势中设置一个振荡幅度的绝对值。
但是要记住,如果幅度大于所选的阈值,这并不表示我们看到了新的趋势!所以不要马上急着立刻开启仓位,您需要使用当前的动态来确认这些数据。
使用阈值绝对值看起来比估算相对幅度值更加有效,因为那在随机不稳定过程的条件下很难定义。当然,这是一个很大的简化,但是在实际应用中它的结果还不错。不使用它,您将会面临严重问题和复杂的理论计算,因为平盘和趋势的边界是模糊逻辑中的问题。
让我们看一下代码段 (用于买入入场):
//---减少与入场交易时缺乏明确趋势有关的风险------- //在较低时段模拟烛形的方向: Close[2] > Open[2] && //在历史中第二个烛形方向向上 (М1) Close[1] > Open[1] && //前一个烛形方向向上 (М1) //在较高时段模拟移动平均的方向: MA5_cur > MA5_2p && MA60_cur > MA60_2p && //向上的移动平均: 使用周期数为5和60的移动平均 (М1) //在较低时段中模拟移动平均的继承: MA5_cur > MA8_cur && MA8_cur > MA13_cur && //在M1上构建三个移动平均的 "层次" (斐波那契周期数:5,8,13), 这是上涨移动的间接迹象 //模拟当前价格相对于较低时段移动平均的位置: Bid > MA5_cur && Bid > MA8_cur && Bid > MA13_cur && Bid > MA60_cur && //当前价格在M1上超过了 МА (5,8,13,60),这是一个上涨变化的间接迹象 //在较高时段中模拟烛形方向: C_prev_m15 > O_prev_m15 && //前面柱形向上方向 (М15) //在较高时段模拟移动平均的方向: MA4_cur_m15 > MA4_2p_m15 && //周期数为4的 МА 向上 (М15) //在较高时段中模拟移动平均的继承: MA4_prev_m15 > MA8_prev_m15 && //在M15上构造两个移动平均的“层次”(周期数为 4 和 8), 这是上涨变化的间接迹象 //模拟当前价格与较高时段移动平均的相对位置: Bid > MA4_cur_m15 && //当前价格超过 МА4 (М15), 这是上涨变化的间接迹象 Bid > MA24_cur_h1 && //当前价格超过 МА24 (Н1), 这是上涨变化的间接迹象 //模拟在较低时段当前烛形内部的微趋势,以及进场点: Bid > Open[0] && //在当前烛形中有上涨变化 (М1) //模拟在较高时段之前的处理中有足够的活动: (C_prev_m15 - O_prev_m15) > (0.5*(H_prev_m15 - L_prev_m15)) && //烛"体" 超过 50% 的烛形幅度 (前一个 М15 烛形) (H_prev_m15 - C_prev_m15) < (0.25*(H_prev_m15 - L_prev_m15)) && //修正深度的限制是少于烛形幅度的 25% (前一个 М15 烛形) H_prev_m15 > H_2p_m15 && //超过局部阻力水平而上涨(两个 М15 烛形) O_prev_m15 < H_prev_m15 && O_prev_m15 > L_prev_m15 && //具有相对于当前烛形开盘价的烛芯 (前一个 М15 烛形) //模拟在较低时段之前的处理中有足够的活动: (Close[1] - Open[1]) > (0.5*(High[1] - Low[1])) && //烛"体"超过 50% 的烛形幅度 (前一个 М1 烛形) (High[1] - Low[1]) > 70*Point && //之前烛形的幅度超过阈值 (排除明显的平盘) (High[2] - Close[2]) < (0.25*(High[2] - Low[2])) && //修正深度限制是少于 20% 的烛形幅度 ( М1 数据历史中的第二个柱) High[1] > High[2] && //上涨趋势在局部阻力水平之上 (两个 М1 烛形) Open[1] < High[1] && Open[1] > Low[1] ) //相对当前烛形的开盘价,具有烛芯(前一个 М1 烛形)
图 4. 入场算法中的模块: 减少与入场交易时缺乏明显定义的趋势相关的风险
说明:
- Open[1], Close[1] — 对应的前一个柱 (М1)的开盘价和收盘价;
- МА5_cur, MA8_cur, MA13_cur, MA60_cur — 在当前柱上,周期数分别为5,8,13和60的移动平均值 (М1);
- MA4_cur_m15, MA4_prev_m15, MA4_2p_m15 — 在报价历史中,使用周期数为4计算的前一个柱和第二个柱上的移动平均值 (М15);
- MA8_prev_m15 — 在报价历史中,使用周期数为8计算的前一个柱的移动平均值 (М15).
我们通过同时模拟在两个时段(M1和M15)上的明确定义的趋势来减小这种风险:
- 之前的烛形和仓位开启方向一致 (在 М1 上的两个烛形和在 М15 上的一个烛形);
- 移动平均的方向 (在 М1 的两个移动平均, 在 М15 上一个移动平均);
- 移动平均的层次 (在 M1 上三个移动平均,在 M15 上两个移动平均);
- 当前价格与移动平均的相对位置 — 在 М1 上三个移动平均.
这种"一系列度量"很大程度上增加了仓位入场点在明确定义的趋势之内的概率,并且这是同时考虑了两个时段的。对应地,掉入平盘区域、随机波动、趋势不明确区域的概就减小了。与这种负面因素相关的风险也就减小了。
这个例子是针对买入入场的,对于卖出, 要使用相反的算法 — 烛形和移动平均都要向下,而不是向上。入场点应当低于指定的移动平均。
选择指标计算周期数相关的风险
每个交易者都是基于个人的经验来设置指标周期数,包括移动平均。有些人喜欢周期数为200的移动平均,有些人把周期数设为 50, 而有些人根据斐波那契序列来设置周期数。我们是根据直觉来设定指标设置的(首先,我们最感兴趣的是指标的周期数)。
这种直觉的原因是传统的分析方法没有提供机制来在特定时刻识别频率调制振荡的机制,这在设置指标周期数的时候会引起不确定性。当然,有些方法可以构建适应性函数 (Kaufman, FRAMA etc.), 但是,它们的算法也没有考虑到不断改变的市场振荡频率。
让我们探讨一个部分解决方案: 我们使用传统的分析方法,再在定义移动平均周期数时加上一些逻辑。我们将使用一些与时间相关的常数因素,在这一原则的有利的事实是,大时段的蜡烛的界限内的蜡烛走势分形的水平,但只有当这些蜡烛灯芯(阴影)。如果没有烛芯,变化可能继续而不在下一个烛形产生分形。
我们比较标准的时段和斐波那契序列的数字(接近的大小),结果,我们得到了在时段间和移动平均计算周期数之间的近似对应关系:
- 1 分钟 — 最接近的斐波那契数值 1 (分钟, 这是一个轴点);
- 5 分钟 — 最接近的斐波那契数值 5 (分钟);
- 15 分钟 – 最接近的斐波那契数值 13 (分钟);
- 1 小时 (60 分钟) — 最接近的斐波那契数值 55 (分钟);
- 4 小时 (240 分钟) — 最接近的斐波那契数值 3 (小时), 5 (小时), 233 (分钟);
- 1 天 (24 小时) — 最接近的斐波那契数值 21 (小时);
- 5 天 (交易周, 对于外汇市场是 120 小时) — 最接近的斐波那契数值 89 (小时) 和 144 (小时).
除此之外,我们还可以推荐一个选项来最小化移动平均的延迟:
- 只在每个时段中使用序列中的前几个数字: 1 (轴点), 3, 5, 8, 13;
- 以复杂的方式使用它们: 把它们按照等于时段的比例转换为更小的时段。使用最小的周期数来计算移动平均可以减少这些功能的延迟,
结果,我们得到了一系列用于不同时段的移动平均的数值集合 (以四个时段为例):
- 对于 М1: 移动平均的周期数为 5, 8, 13, 55 (或者 60 =1 小时), 233 (或者 240 = 4 小时);
- 对于 М15: 移动平均的周期数为5,8,13,55 (或者 60=4 小时?);
- 对于 Н1: 移动平均的周期数为5, 8, 13, 21 (或者 24 = 1 天), 89, 144 (或者 120 = 5 天);
- 对于 D1: 移动平均的周期数为 5, 8, 13, 21 (或者 24 = 1 交易月).
当然,这只是一系列移动平均的例子,您可以自由添加您自己的数值。然而,这种选择移动平均周期数的原则是有其存在理由的,因为很多因素,包括交易时段的起始和结束,统计时段,支付股利,等等,都有明确定义的时间段。这样,指标周期数(本例中的移动平均)的逻辑性选择可以使我们考虑到市场事件的频率,从而在一定程度上减少风险。
我们将在开发其他所描述的模块的移动平均中使用这些推荐值。
入场交易时使用挂单有关的风险
这里我们的意思是依赖于挂单(而不是市场即时订单)来设置目标水平的策略,更为常见的是,挂单使用在价格退出盘整区域的有关策略中,
在各种这样的策略中,让我们讨论一个在盘整区域的两边使用一对挂单,希望其中一个订单正确工作,而在第一个挂单被触发后立即删除第二个挂单。r the first one is triggered. 请注意,使用挂单来确定入场点也是有风险的,挂单的水平通常设置在想要的价格达到之前,例如,挂单的水平按照盘整区域幅度的百分比来定义,这就和真实的价格动态没有关系,
事实上,这就是挂单与市场单相比的主要缺点– 无法在入场时有负面因素出现时避免建立仓位. 一旦达到目标价位,市场动态变得不利于这个挂单时,还是会入场交易,而这将会造成亏损。
所以,如果您还是想在某种固定水平进行交易时,更合理的方法是在入场算法内部虚拟进行处理,而不是使用标准的挂单。只有在侦测到所需动态时,价格穿过固定水平时才进入市场。当然,这种方法比传统的挂单要复杂,因为我们需要额外的算法来控制价格穿过虚拟水平时的动态(也需要编程能力来开发这样所需的算法),但是这将可以使您避免“摸黑”交易,而这在使用传统的挂单中是无法避免的。
这种方法也有它的缺点,当价格达到所需的水平,我们使用市场单(而不是挂单)进入市场,这在经纪商平台的反应会比已经设置的挂单要慢。如果有很多订单,执行的延迟可能因为订单的优先级而增加。如果在入场时价格有较大变化,可能会出现滑点。
这样,我们需要选择是使用挂单“摸黑”进入市场的风险还是市场单执行延迟的风险。与此同时,使用虚拟水平的优点是,当价格达到了定义的水平时,如果没有所需的进场条件,系统可以自动取消进场。
我个人的观点是:因为使用挂单会增加风险,还是有必要不适用这样的订单来减少这种风险。这和其他事情一样也是公平的,只是让市场来决定价格变化的幅度。我们的唯一目的是在开发的某个阶段,使用分析方法来控制这样的变化。
入场交易之后价格变化幅度不确定性相关的风险
许多交易者的典型错误是他们过于执着于定义某个目标水平,考虑到价格变化的随机和不稳定过程,最终的幅度是个概率值。和上面所描述的挂单一样,设置固定的目标利润水平 (例如定义出场点) 是比较主观的。所以,这种方法经常会导致亏损。
市场退出算法应该具有控制慢化迹象的功能(自适应函数)或控制某个级别的固定振幅值的功能(已开启仓位的入场水平,当前最高价或最低价)。我们还将对第二个选项中加入风险限额的控制 — 同时加在仓位和全部存款中。我们将会使用最后一个简单一些的版本。让我们看一下代码段:
//减少与入场交易时价格变化幅度不确定相关的风险-- //跟踪固定的利润值 (每个仓位): (Bid > OrderOpenPrice() && (Bid - OrderOpenPrice()) >= 100*Point) //在利润区域内的退出条件(影子获利) || //管理最大可用的价格偏移 //和入场交易后当前最大值比较: (shift_buy >= 1 && //与入场点相差不少于一个柱 Time_cur > OrderOpenTime() && Max_pos > 0 && OrderOpenTime() > 0 && OrderOpenPrice() > 0 && //这是入场后的当前最大值 Max_pos > OrderOpenPrice() && //当前最大值在有利润区域 Bid < Max_pos && //有反向的变化 (Max_pos - Bid) >= 200*Point) //距离退出市场的当前最大值的偏移 || //跟踪预先定义的风险限额 (每个仓位): (Bid < OrderOpenPrice() && (OrderOpenPrice() - Bid) >= 200*Point) //入场条件在亏损区域 (影子止损) || //跟踪预先定义的风险限额 (全部存款): (AccountBalance() <= NormalizeDouble( (Depo_first*((100 - Percent_risk_depo)/100)), 0)) ) //如果用于全部存款的风险限额在当前的交易中被超过
图 5. 退出算法模块: 减少在入场交易后价格变化幅度不确定相关的风险
说明:
- OrderOpenPrice() — 入场交易价格;
- Shift_buy — 相对入场点的偏移(在 М1 中的柱数) (在定义仓位最大值的时候需要);
- Max_pos — 开启仓位中的最高水平;
- AccountBalance() — 当前资金余额;
- Depo_first — 初始存款资金数;
- Percent_risk_depo — 最大允许亏损占全部存款的百分数.
这类风险是使用下面的方法来减少的:
- 管理每个仓位的固定利润,实际上,是一个“影子”获利值。
- 管理在入场交易之后所允许的距离当前最高价(对于买入)或者最低价(对于卖出)的价格偏移。
- 管理每个仓位的预先定义的风险限额,是一个“影子”止损值。
- 管理对于全部存款的预先定义的风险限额。
在所有这些情况下,我们控制着相对于它们变化水平的某个幅度值,包括入场水平,在开启仓位中的最大值和初始存款。所以,和严格设置目标水平不同,这些水平不是固定的。
我们已经探讨了在关闭买入仓位中的例子模块,对于卖出模块,只有在交易方向上有改变。使用的不是仓位内的当前最大值 (Max_pos), 而是使用的当前最小值(Min_pos)。
在下一个部分中,我们会探讨考虑到价格变化速度的风险,它在市场价格剧变的时候特别重要。
入场交易之后价格剧变相关的风险
一种形式的局部趋势反转是价格在短时间内的大幅度上涨和下跌,在货币对中一种货币暴涨总是意味着另一种的暴跌。如果有开启的仓位,并且价格剧变的方向不利于它时就特别危险。在这种情况下,存款数量小的话就会都亏光了。
这个问题的实质
- 价格剧变的速度没有给市场参与者留下时间来足够地回应它们,
- 现代的分析方法也没有提供机制来识别快速价格崩塌所关联的动态结构。
- 如果有开启的仓位,市场参与者在价格剧变的时候完全没有办法防御它。在早期阶段很难侦测到价格的剧变,更别说对它做出回应了,因为主要的价格尖峰已经过去了,或者市场在经纪商和银行的链条中受阻了。
结果,市场参与者会承受巨大损失。例如,在2010年5月6日,道琼斯股票指数在6分钟之内下泻1000点,根据专家估计,市场蒸发了一万亿美元的市值。
更近的一个例子 (图 6) is Brexit(英国退出欧盟), 它导致 GBPUSD 在2016年6月24日这一天一下暴跌了 560 个点,在一分钟内它就下跌了473个点。
图 6. GBPUSD 在2016年6月24日的价格暴跌
对于价格剧变有三个全局因素:
- 市场本身的自然现象. 剧变不是来源于外部,而是市场动态的自然操作。除了其他之外,它可能导致价格的急剧变化(例如,因为市场参与者增加,包括交易机器人)。例如,根据媒体报告,在美国股市,在一秒钟之内就有数以千计的超快速波动。
- 分析发展水平. 用于识别这样的市场操纵的方法还不够完美. 适当的反应需要能够在几分之一分钟之内就能够进行状态分析,而市场平台中很少有以秒为单位的时段。
- 在金融市场调节中没有合适的立法。例如,没有法律机制来制止做市商人为操纵价格。
这里是一个例子,关于一个基于 MACD 的 EA 交易是怎样没有时间来回应在 USDCHF 价格上的急跌的。
图 7. 这个基于 MACD 的 EA 没有时间来回应 USDCHF 在2015年10月2日的价格崩溃。
图 7 显示了,EA开启了两个仓位 — 一个在价格崩溃之前 (箭头 1),另一个在那之后 (图 2)。它没有回应价格的崩塌是因为它就是“没有注意到”它。
所以,如果您有一个开启的仓位,就有在价格崩溃或者飙升的时候损失很大部分存款的风险。这意味着仓位的关闭算法应该有特别的保护模块。
让我们看一下代码段:
if( //减少入场交易时价格剧变相关的风险---------------------- (Bid < Open[0] && (Open[0] - Bid) >= 100*Point && (Time_cur - Time[0]) <= 20) //在价格剧变时的退出条件 (在任何区域) (参考点 - М1 当前柱的开盘价) || (Bid < O_cur_m15 && (O_cur_m15 - Bid) >= 200*Point && (Time_cur - Time_cur_m15) <= 120) //在价格剧变时的退出条件(在任何区域) (参考点 - М15 当前柱的开盘价) || ((Time_cur - OrderOpenTime()) > 60 && Close[1] < Open[1] && (Open[1] - Close[1]) >= 200*Point) //在价格剧变时的在任何区域的退出条件 (参考点 - М1 前一个柱的幅度) ||
图 8. 退出算法中的模块: 减少与入场交易后价格崩盘相关的风险
仓位开启后价格崩盘的风险是按下面的方法减少的:
- 价格反转偏移(崩盘)的限额是通过与不同时段 (在我们的例子中,是 М1 和 М15)当前柱开盘价相比较而定义的,也定义了这种崩盘的最大可接受时间段长度。
- 最大允许的价格剧变幅度是在M1上用之前完成的柱的形式来设置的(因为这是一个分钟柱,也就间接指定了剧变的时间跨度)。
这样,剧变是既在当前柱的开端进行跟踪(使用的是与前一柱的变化比较),在它的发展过程中也会跟踪的。如果出现了任何指定的条件 (通过“或”逻辑), 仓位就会被关闭 — 风险就被最小化。
在这个例子中展示了用于关闭买入仓位的模块,如需关闭仓位, 就考虑价格走向相反的方向。
与只使用一个时段有关的风险
价格的变化在不同时段的图表中的反映是不同的,在较低时段中出现的趋势,如果我们在更高的时段上研究它,可能只是个小的修正。
所以,我们应该在多个时段来分析价格的动态 - 一个是不够的。
应该使用多少个时段来分析?这个问题的答案在于你自己,我个人同时使用四个时段(在四个屏幕上),因为:
- М1: 这个时段适合用来显示趋势的反转(包括全局的反转)以及快速的市场崩溃;
- М15: 图表上这个时段的柱形经常反映了在较低时段(M1和M5)上形成,已经完成的快速市场崩溃的动态结构;
- Н1: 这个时段的柱形是自然的时间限制器 (包含了交易市场的日程,宏观经济指数、新闻的发布,等等);
- D1: 这个时段的柱形是自然的限制器(包含了一周内的交易日).
我相信,这些时段的组合是有效的,因为它使您可以正确分析市场的动态。当然,我们需要一些价格变化中“交易量度量”相关的信息,这在金融市场上操作上是不可或缺的。
因为只使用一个时段不可避免就地增加了交易风险,入场算法的代码应该包含对烛形、移动平均和其他指标的在多个时段的分析。
与只使用一种分析类型(技术分析或者基本分析)有关的风险
价格的变化是由很多因素所影响的,市场是一个基于参与者经济方面兴趣的行为系统,技术分析(交易机器人就是基于此)只使用了一类数据 — 某种金融资产的价格水平,反过来,基本分析也是只考虑了一类数据(例如,某个宏观经济因素),很明显,这样的分析是不完整的,只有一个方面,也就会不准确。只分析价格而不考虑其变动因素或只关注基本指标而不考虑价格的实际动态是不正确的。
把这两种分析结合在一起是比较合理的,因为它们在逻辑上是相辅相成的。一般的基本因素(但不是绝对)预定价格运动的方向,而技术因素会进行确认。但是,相对于技术性因素而言,基本因素不是绝对的。
有时,市场对技术因素的反应更多,而不是基本因素,例如达到历史高点时。一个显著的例子是比特币周期性崩溃(有时是每天20%),在达到历史高位后立即崩溃。然而,比特币的例子并不是完全有代表意义,因为数字加密货币的基本分析是有问题的,因为它有市场的特殊性。
但是,在外汇交易还有特别是股票市场中,基本面分析的影响是很明显的。例如,USDCHF的崩溃(在2015年10月)是因为瑞士央行"解除了"瑞郎和欧元汇率的捆绑。
所以,我相信不应该试图定义这些分析类型的优先级,而是应该联合起来使用它们。但是,有一个问题: 我们怎样才能在自动化交易中使用基本面分析呢?因为交易系统算法只能使用市场技术面的参数。
我们提出了两种选项可以把基本面分析嵌入到交易策略中。
- 选项 1. 在交易策略算法中实现基本面分析参数,把它们转换为技术性参数 (例如,在定义了经济日历上数据的行为逻辑后再输入这些数据)。
- 选项 2. 在EA交易内部人工限制市场入场的方向 (只在对应了基本面分析参数的方向上交易)。
我们可以看到,在算法中使用基本面分析很不方便,但是这是正确的方法。在人工交易中组合使用两种方法会更简单,新手分析师或者交易者应该这样做。
不与市场动态相关的风险
外部因素 — 操作性, 金融性和法律性 — 也是交易过程的一部分。它们在风险出现中起着同等重要的作用。所以,如果有可能,我们应当在开发交易系统的时候要考虑到它们,
让我们定义它们的列表。
与市场动态无关的风险的分类
这里是与价格动态无关的最常见的可能风险。
- 与交易系统结构相关的风险。
- 与超过存款亏损限额 (根据存款管理投资者的风险限额) 相关的风险。
- 与交易条件负面改变相关的风险。
- 由经纪商交易服务器连接质量决定的风险。
- 与经济商端或者客户端对自动化交易许可有关的风险。
- 与金融市场法律改变有关的风险。
让我们仔细看看它们以及减少它们的方法。
交易系统结构相关的风险
主要原则: 交易系统的结构应当考虑到风险的结构. 它应当包含对上面提到的尽可能多的风险的防护,这会提高交易的效率。
但是,当我们增加了最小化风险的模块数量时,我们不可避免地增加了过滤器的数量,因为任何防止风险的方法实际都是一个过滤器。结果,我们会面临在交易机器人的入场算法中的“过多过滤”的问题。同时,大多数交易者都认为机器人应该活跃地交易,每天至少都要开启仓位。从这点上考虑,交易者就像是机器人的客户,这样的要求从他们的角度上非常符合逻辑。但是,我相信这是不对的,因为这个过程很自然,
任何EA算法都回模拟复杂的动态,而不可避免地简化它们,错误是与把某种EA的模型与市场动态不完全地匹配有关的。
每个开发者都知道,在入场交易次数和入场算法的过滤数量之间是有关系的,过滤的数量越大,入场交易次数就越少,反之亦然。一般来说,过滤增多的时候,投资成果会越好,但是,当然它依赖于过滤器的内容。您需要在入场数量和投资成果之间找到一个平衡点,或者更明确地说,每个交易系统的最大风险(存款回撤),这被称为传统的优化。
但是什么是过滤呢?
如果这意味着从整个频谱中分配有用的信号,那么我们需要明确的标准。传统的分析方法无法提供它们。传统指标的激活很难被称为“正确的”过滤这样一个复杂价格变化过程。例如,如果我们应用埃利奥特波结构或技术分析模式来寻找一个有用的信号,我们将认识到它们不适合分析,因为每个交易者在同一张图表上都有不同的判断。
因此,交易系统结构应通过梳理这些风险参数的临界值降低风险的确定。但是有很多风险,而且过滤的程度随着它们的数量而增长。因此,在评估单个EA的效率时,最重要的不是条目数目,而是一个稳定的(尽管是低的)利润,并具有可接受的风险(回撤)。在这种情况下,入场交易的次数(在单个金融工具上进行测试时)可能无关紧要,可以通过几种货币对同时进行交易来增加利润。
因此得出下面的结论:
要开启的仓位数量是评估EA交易质量的次要因素,主要的是在取得利润的同时它的相对稳定性。
交易系统的效率应在若干金融工具上进行评估。这提高了模拟的质量和最终结果:
- 交易策略是在各种市场动态的操作中测试的;
- 如果在几个交易品种中取得了正面的结果,存款上的总利润增长就可以满足投资者的利润目标要求。
这样,交易策略的优化应该可以缩减到选择当在几个金融资产中测试时显示出利润设置。
与超过存款亏损限制有关的风险
即使在交易之前,也需要设置交易存款的风险限制,这可以是一个固定值和绝对值(资金角度)或者相对(初始存款总量百分比)数量。如果达到这个值,就停止交易。
如果你委托一位更有经验的交易员管理你的账户,在协议中设定风险限额。
如果你自己交易,你需要在入场算法中添加代码(如果超过了风险限额,就禁止入场交易),并将其添加到出场(我们在前面讨论过的“在市场进入后价格波动幅度的不确定性相关的风险”)。存款的双重控制是必要的,因为首先,存款风险的限制是在有一个开启仓位(这是固定在市场退出算法)实现的。在此之后,我们需要禁用后续的入场,因为存款的风险限额已经实现(这是固定在市场进入算法之前的模块)。
让我们看一下代码段:
//管理与限制客户存款总体风险有关的金融参数------------------------------- if(kol < 1) //没有订单 { if(AccountBalance() <= NormalizeDouble( (Depo_first*((100 - Percent_risk_depo)/100)), 0))//如果之前已经达到了全部存款的风险限额 { Print("入场被禁止-之前达到了风险限额=",Percent_risk_depo, " 全部存款 % =", Depo_first); Alert("入场被禁止-之前达到了风险限额=",Percent_risk_depo, " 全部存款 % =", Depo_first); return; } if(AccountFreeMargin() < (1000*Lots)) //在当前账户上建立仓位的保证金不够 { Print("保证金不足. 账户可用保证金 = ",AccountFreeMargin()); Alert("保证金不足. 账户可用保证金 = ",AccountFreeMargin()); return; //...然后退出 } } //--------------
图 9. 入场算法之前的模块: 减少超过存款亏损限额有关的风险
第一个代码块管理了客户的存款状态 (AccountBalance() 变量). 可自定义变量:
- Depo_first — 初始存款资金数;
- Percent_risk_depo — 存款的亏损限额 (其初始值的百分比).
如果账户的亏损达到了在 Percent_risk_depo 变量中设置的值,算法就会被触发。同时,禁止入场交易,然后我们退出程序。
第二个代码块管理了当允许入场交易时账户的保证金,当保证金金额低于某手数的保证金要求时就会触发这个算法。入场交易被禁止,然后我们退出程序。
与不利交易条件有关的风险
可能有: 经纪商的报价质量; 当开启或者关闭仓位时的点差扩大; 当执行订单时的价格滑点; 订单执行延迟。
所有这些可能对交易结果影响很大 (直至存款亏光), 所以您需要监控相关的参数。特别是您需要自动跟踪价格、点差、入场和出场的算法触发时间,并且把它们与真正的开启和关闭仓位的数据作比较。
您可以在您的交易系统中自行开发这样的模块。
由经纪商服务器连接质量决定的风险
交易服务器的连接质量依赖于两个因素:
- 经纪商端交易服务器的状态;
- 客户端的互联网连接.
第二个因素可以通过把客户端放到外部服务器上加以消除,第一个因素可以通过在交易系统算法中加入代码用程序来验证。
让我们看一下代码段:
if(IsConnected() == false) //检查客户终端和经纪商服务器的主连接 { Print("入场被禁止-经纪商服务器离线"); Alert("入场被禁止-经纪商服务器离线"); return; }
图 10. 减少与经纪商交易服务器连接质量有关风险的模块
图 10 显示了可以用于监控与经纪商服务器连接的代码段,它需要构建在EA交易的入场算法之前,当这些条件出现时,就不能开启仓位。
经纪商与客户方面对自动交易许可相关的风险
有的时候,交易策略发送订单到客户终端,但是它没有被执行,然而,交易策略本身可能没有限制交易。可能的原因:
- 在客户端,客户终端的设置中禁止了自动交易;
- 经纪商禁止在当前账户中进行交易.
为了消除这些风险,需要在交易系统程序中控制是否允许自动化交易。
让我们看一下代码段:
if(IsTradeAllowed() == false) //检查是否能用EA来进行交易 (经纪商数据流,交易许可) { Print("禁止入场-经纪商数据流繁忙以及/或者不允许机器人的交易 :", IsTradeAllowed()); Alert("禁止入场-经纪商交易数据流繁忙以及/或者不允许机器人进行交易 :", IsTradeAllowed()); return; } if( !AccountInfoInteger(ACCOUNT_TRADE_EXPERT) ) //检查交易账户属性 { Print("自动化交易被禁止,账户 :", AccountInfoInteger(ACCOUNT_LOGIN), "位于交易服务器端"); Alert("自动化交易被禁止,账户 :", AccountInfoInteger(ACCOUNT_LOGIN), "位于交易服务器端"); return; } if(IsExpertEnabled() == false) //检查是否允许在客户端载入EA交易 { Print("禁止入场- 在终端中机器人的交易许可被禁止 :", IsExpertEnabled()); Alert("禁止入场- 在终端中机器人的交易许可被禁止 :", IsExpertEnabled()); return; } if(IsStopped() == true) //检查结束mql4程序执行的命令 { Print("禁止入场-结束mql4程序执行的命令被触发"); Alert("禁止入场-结束mql4程序执行的命令被触发"); return; }
图 11. 用于减少与经纪商端和客户端对自动化交易许可有关风险的模块
上面的代码段控制了经纪商和客户端对于自动化交易许可的状态,当您符合这些条件的任意部分时,入场交易就被禁止。
与金融市场法规改变相关的风险
这些是金融市场行业中直接或间接影响客户风险的关系规则。各国制定立法规范股票和金融市场的关系。将来,与各种违规行为相关的许多风险应该减少。
考虑到所属风险的EA交易实例
我们已经识别并审查了与市场动态有关的风险,另外,我们已经定义了用来减少它们的特定解决方案。
通过把特定的模块插入到EA中(在入场算法之前,以及在入场及退场算法之中),这些风险就可以减少。每个模块管理了某种风险,
主要的分析元素就是不同时段的烛形。动态是通过在烛形内部(单个结构分析)和烛形之间(结构组分析)进行分析的。
下面是一个简单EA的代码,它包含了用于减少一些上述风险的功能。请注意,在传统指标当中,它只使用了移动平均(考虑到上面描述的限制)。
EA 代码是用于5位小数代码报价的(或者对于 USDJPY 来说是3位小数):
//+------------------------------------------------------------------+ //| Reduce_risks.mq4 | //| Copyright 2017, Alexander Masterskikh | //| | //+------------------------------------------------------------------+ #property copyright "2017, Alexander Masterskikh" #property link "https://www.mql5.com/en/users/a.masterskikh" input double TakeProfit = 600; //获利 input double StopLoss = 300; //止损 input double Lots = 1; //手数 input int Depo_first = 10000; //初始客户存款金额 input int Percent_risk_depo = 5; //针对全部存款的最大允许风险 (客户初始存款的百分比) input bool test = false; //设置: true - 用于测试 (默认为 false,用于交易) //------------------------------------------------------------------------------------------------- void OnTick(void) { //---定义变量--- int f,numb,kol; double sl_buy, tp_buy, sl_sell, tp_sell; double L_prev_m15, L_2p_m15, L_3p_m15; double H_prev_m15, H_2p_m15, H_3p_m15; double O_cur_m15, O_prev_m15, O_2p_m15, C_prev_m15, C_2p_m15; double MA4_cur_m15, MA4_prev_m15, MA4_2p_m15, MA5_prev_m15, MA8_cur_m15, MA8_prev_m15, MA8_2p_m15; double MA8_cur, MA8_prev, MA8_2p, MA8_3p, MA5_cur, MA5_prev, MA5_2p, MA13_cur, MA13_prev, MA13_2p, MA60_cur, MA60_prev, MA60_2p, MA24_cur_h1; double C_prev_h1, O_prev_h1, H_prev_h1, L_prev_h1, H_2p_h1, L_2p_h1; datetime Time_cur, Time_cur_m15; double shift_buy, shift_sell; double Max_pos, Min_pos; //-------- //管理技术参数 (状态和许可) - 在经纪商端和客户端------------------------------- if(test==false) //检查: 测试还是交易 (测试 - true, 交易 - false) {//当在历史数据中测试时,参数不用检查--- if(IsConnected() == false) //检查客户终端与经纪商服务器的主连接的状态 { Print("禁止入场-经纪商服务器离线"); Alert("禁止入场-经纪商服务器离线"); return; } if(IsTradeAllowed() == false) //检查是否能用EA来交易 (经济商流程,交易许可) { Print("禁止入场-经济商交易数据流忙以及/或者EA交易许可被禁止 :", IsTradeAllowed()); Alert("禁止入场-经纪商交易数据流忙以及/或者EA交易许可被禁止:", IsTradeAllowed()); return; } if( !AccountInfoInteger(ACCOUNT_TRADE_EXPERT) ) //检查交易账户属性 { Print("自动交易被禁止,账户 :", AccountInfoInteger(ACCOUNT_LOGIN), "在交易服务器端"); Alert("自动交易被禁止,账户 :", AccountInfoInteger(ACCOUNT_LOGIN), "在交易服务器端"); return; } if(IsExpertEnabled() == false) //检查是否允许在客户端载入EA交易 { Print("禁止入场- 在终端中机器人的交易许可被禁止 :", IsExpertEnabled()); Alert("禁止入场- 在终端中机器人的交易许可被禁止 :", IsExpertEnabled()); return; } if(IsStopped() == true) //检查结束mql4程序执行的命令 { Print("禁止入场-结束mql4程序执行的命令被触发"); Alert("禁止入场-结束mql4程序执行的命令被触发"); return; } } //当在历史数据中做测试时不检查的参数到此结束 //管理使用的交易品种在终端中的报价数量不足的问题--- if(Bars<100) { Print("当前图表中的柱的数量不够"); return; } //管理在所需时段放置 EA ---- if(Period() != PERIOD_M1) { Print("EA 放置不正确, 把 EA 放到时段 :", PERIOD_M1); Alert("EA 放置不正确, 把 EA 放到时段 :", PERIOD_M1); return; } //管理把EA放到所需的金融工具中---- if(Symbol() != "EURUSD" && Symbol() != "USDCHF" && Symbol() != "USDJPY") { Print("EA 放置不正确-无效的金融工具"); Alert("EA 放置不正确-无效的金融工具"); return; } //---------- //管理与客户存款限额有关的财务参数------------------------------- if(kol < 1) //没有订单 { if(AccountBalance() <= NormalizeDouble( (Depo_first*((100 - Percent_risk_depo)/100)), 0))//如果之前已经达到了全部存款的风险限额 { Print("入场被禁止-之前达到了风险限额=",Percent_risk_depo, " 全部存款 % =", Depo_first); Alert("入场被禁止-之前达到了风险限额=",Percent_risk_depo, " 全部存款 % =", Depo_first); return; } if(AccountFreeMargin() < (1000*Lots)) //在当前账户上建立仓位的保证金不够 { Print("保证金不足. 账户可用保证金 = ",AccountFreeMargin()); Alert("保证金不足. 账户可用保证金 = ",AccountFreeMargin()); return; //...然后退出 } } //-------------- //变量值: L_prev_m15 = iLow(NULL,PERIOD_M15,1); L_2p_m15 = iLow(NULL,PERIOD_M15,2); L_3p_m15 = iLow(NULL,PERIOD_M15,3); H_prev_m15 = iHigh(NULL,PERIOD_M15,1); H_2p_m15 = iHigh(NULL,PERIOD_M15,2); H_3p_m15 = iHigh(NULL,PERIOD_M15,3); O_cur_m15 = iOpen(NULL,PERIOD_M15,0); O_prev_m15 = iOpen(NULL,PERIOD_M15,1); O_2p_m15 = iOpen(NULL,PERIOD_M15,2); C_prev_m15 = iClose(NULL,PERIOD_M15,1); C_2p_m15 = iClose(NULL,PERIOD_M15,2); Time_cur_m15 = iTime(NULL,PERIOD_M15,0); C_prev_h1 = iClose(NULL,PERIOD_H1,1); O_prev_h1 = iOpen(NULL,PERIOD_H1,1); H_prev_h1 = iHigh(NULL,PERIOD_H1,1); L_prev_h1 = iLow(NULL,PERIOD_H1,1); H_2p_h1 = iHigh(NULL,PERIOD_H1,2); L_2p_h1 = iLow(NULL,PERIOD_H1,2); MA4_cur_m15 = iMA(NULL,PERIOD_M15,4,0,MODE_SMA,PRICE_TYPICAL,0); MA4_prev_m15 = iMA(NULL,PERIOD_M15,4,0,MODE_SMA,PRICE_TYPICAL,1); MA4_2p_m15 = iMA(NULL,PERIOD_M15,4,0,MODE_SMA,PRICE_TYPICAL,2); MA5_prev_m15 = iMA(NULL,PERIOD_M15,5,0,MODE_SMA,PRICE_TYPICAL,1); MA8_cur_m15 = iMA(NULL,PERIOD_M15,8,0,MODE_SMA,PRICE_TYPICAL,0); MA8_prev_m15 = iMA(NULL,PERIOD_M15,8,0,MODE_SMA,PRICE_TYPICAL,1); MA8_2p_m15 = iMA(NULL,PERIOD_M15,8,0,MODE_SMA,PRICE_TYPICAL,2); MA8_cur = iMA(NULL,PERIOD_M1,8,0,MODE_SMA,PRICE_TYPICAL,0); MA8_prev = iMA(NULL,PERIOD_M1,8,0,MODE_SMA,PRICE_TYPICAL,1); MA8_2p = iMA(NULL,PERIOD_M1,8,0,MODE_SMA,PRICE_TYPICAL,2); MA8_3p = iMA(NULL,PERIOD_M1,8,0,MODE_SMA,PRICE_TYPICAL,3); MA5_cur = iMA(NULL,PERIOD_M1,5,0,MODE_SMA,PRICE_TYPICAL,0); MA5_prev = iMA(NULL,PERIOD_M1,5,0,MODE_SMA,PRICE_TYPICAL,1); MA5_2p = iMA(NULL,PERIOD_M1,5,0,MODE_SMA,PRICE_TYPICAL,2); MA13_cur = iMA(NULL,PERIOD_M1,13,0,MODE_SMA,PRICE_TYPICAL,0); MA13_prev = iMA(NULL,PERIOD_M1,13,0,MODE_SMA,PRICE_TYPICAL,1); MA13_2p = iMA(NULL,PERIOD_M1,13,0,MODE_SMA,PRICE_TYPICAL,2); MA60_cur = iMA(NULL,PERIOD_M1,60,0,MODE_SMA,PRICE_TYPICAL,0); MA60_prev = iMA(NULL,PERIOD_M1,60,0,MODE_SMA,PRICE_TYPICAL,1); MA60_2p = iMA(NULL,PERIOD_M1,60,0,MODE_SMA,PRICE_TYPICAL,2); MA24_cur_h1 = iMA(NULL,PERIOD_H1,24,0,MODE_SMA,PRICE_TYPICAL,0); kol = OrdersTotal(); Time_cur = TimeCurrent(); if(kol < 1) //如果没有开启的订单,就继续 { //---入场交易算法 - 买入------------------------------------------------------------------------------------------- if( //----减少入场交易时出现较大波动相关的风险 ---- //在最近的历史中模拟没有较大波动: ( High[1] - Low[1]) <= 200*Point && //在较低时段(M1)中限制幅度 ( High[2] - Low[2]) <= 200*Point && ( High[3] - Low[3]) <= 200*Point && (H_prev_m15 - L_prev_m15) <= 300*Point && //在较高时段 (М15) 限制幅度 (H_2p_m15 - L_2p_m15) <= 300*Point && (H_3p_m15 - L_3p_m15) <= 300*Point && (H_prev_m15 - L_3p_m15) <= 300*Point && //把幅度限制在由较高时段柱形(М15)生成的通道内 (High[1] - Low[1]) >= (1.1*(High[2] - Low[2])) && //在报价历史中限制前一柱相对于第二个柱的活动 (High[1] - Low[1]) < (3.0*(High[2] - Low[2])) && //相同 //----减少入场交易时出现阻力水平相关的风险----- //模拟局部阻力水平被当前价格突破的情况: Bid > High[1] && //on М1 Bid > H_prev_m15 && //on М15 //---减少与在入场交易时进入超买区域有关的风险----- //Simulate binding to the start of the wave to decrease the entry probability in the overbought area: ((MA8_prev > Low[1] && MA8_prev < High[1]) || (MA8_2p > Low[2] && MA8_2p < High[2]) || //波段的开始 - 在数据历史中不远于3个柱 (М1) (MA8_3p > Low[3] && MA8_3p < High[3])) && //相同 MA5_prev_m15 > L_prev_m15 && MA5_prev_m15 < H_prev_m15 && //波段的开始 - 在较高时段(М15)的前一个柱 //---减少在入场交易时缺乏明确定义的趋势有关的风险------- //在较低时段模拟烛形的方向: Close[2] > Open[2] && //在历史中第二个烛形方向向上 (М1) Close[1] > Open[1] && //前一个烛形方向向上 (М1) //在较高时段模拟移动平均的方向: MA5_cur > MA5_2p && MA60_cur > MA60_2p && //向上的移动平均: 使用周期数为5和60的移动平均 (М1) //在较低时段中模拟移动平均的继承: MA5_cur > MA8_cur && MA8_cur > MA13_cur && //在M1上构建三个移动平均的 "层次" (斐波那契周期数:5,8,13), 这是上涨移动的间接迹象 //模拟当前价格相对于较低时段移动平均的位置: Bid > MA5_cur && Bid > MA8_cur && Bid > MA13_cur && Bid > MA60_cur && //当前价格在M1上超过了 МА (5,8,13,60),这是一个上涨变化的间接迹象 //在较高时段中模拟烛形方向: C_prev_m15 > O_prev_m15 && //前面柱形向上方向 (М15) //在较高时段模拟移动平均的方向: MA4_cur_m15 > MA4_2p_m15 && //周期数为4的 МА 向上 (М15) //在较高时段中模拟移动平均的继承: MA4_prev_m15 > MA8_prev_m15 && //在M15上构造两个移动平均的“层次”(周期数为 4 和 8), 这是上涨变化的间接迹象 //模拟当前价格与较高时段移动平均的相对位置: Bid > MA4_cur_m15 && //当前价格超过 МА4 (М15), 这是上涨变化的间接迹象 Bid > MA24_cur_h1 && //当前价格超过 МА24 (МН1), 这是上涨变化的间接迹象 //模拟在较低时段当前烛形内部的微趋势,以及进场点: Bid > Open[0] && //在当前烛形中有上涨变化 (М1) //模拟在较高时段之前的处理中有足够的活动: (C_prev_m15 - O_prev_m15) > (0.5*(H_prev_m15 - L_prev_m15)) && //烛"体" 超过 50% 的烛形幅度 (前一个 М15 烛形) (H_prev_m15 - C_prev_m15) < (0.25*(H_prev_m15 - L_prev_m15)) && //修正深度的限制是少于烛形幅度的 25% (前一个 М15 烛形) H_prev_m15 > H_2p_m15 && //超过局部阻力水平而上涨(两个 М15 烛形) O_prev_m15 < H_prev_m15 && O_prev_m15 > L_prev_m15 && //具有相对于当前烛形开盘价的烛芯 (前一个 М15 烛形) //模拟在较低时段之前的处理中有足够的活动: (Close[1] - Open[1]) > (0.5*(High[1] - Low[1])) && //烛"体"超过 50% 的烛形幅度 (前一个 М1 烛形) (High[1] - Low[1]) > 70*Point && //之前烛形的幅度超过阈值 (排除明显的平盘) (High[2] - Close[2]) < (0.25*(High[2] - Low[2])) && //修正深度限制是少于 20% 的烛形幅度 ( М1 数据历史中的第二个柱) High[1] > High[2] && //上涨趋势在局部阻力水平之上 (两个 М1 烛形) Open[1] < High[1] && Open[1] > Low[1] ) //相对当前烛形的开盘价,具有烛芯(前一个 М1 烛形) { //如果在上面指定的买入入场算法条件符合,生成买入入场订单: sl_buy = NormalizeDouble((Bid-StopLoss*Point),Digits); tp_buy = NormalizeDouble((Ask+TakeProfit*Point),Digits); numb = OrderSend(Symbol(),OP_BUY,Lots,Ask,3,sl_buy,tp_buy,"Reduce_risks",16384,0,Green); if(numb > 0) { if(OrderSelect(numb,SELECT_BY_TICKET,MODE_TRADES)) { Print("买入入场 : ",OrderOpenPrice()); } } else Print("建立买入订单出错 : ",GetLastError()); return; } //--- 卖出入场交易算法-------------------------------------------------------------------------------------------------- if( //----减少入场交易时出现较大波动相关的风险 ---- //在最近的历史中模拟没有较大波动: ( High[1] - Low[1]) <= 200*Point && ///在较低时段 (М1) 限制幅度 ( High[2] - Low[2]) <= 200*Point && ( High[3] - Low[3]) <= 200*Point && (H_prev_m15 - L_prev_m15) <= 300*Point && //在较高时段 (М15) 限制幅度 (H_2p_m15 - L_2p_m15) <= 300*Point && (H_3p_m15 - L_3p_m15) <= 300*Point && (H_prev_m15 - L_3p_m15) <= 300*Point && //把幅度限制在由较高时段柱形(М15)生成的通道内 (High[1] - Low[1]) >= (1.1*(High[2] - Low[2])) && //在报价历史中限制前一柱相对于第二个柱的活动 (High[1] - Low[1]) < (3.0*(High[2] - Low[2])) && //相同 //----减少入场交易时出现阻力水平相关的风险----- //模拟局部阻力水平被当前价格突破的情况: Bid < Low[1] && // М1 Bid < L_prev_m15 && // М15 //---减少入场交易时进入超卖区域的相关风险----- //模拟绑定到波段的开始来减少在超卖区域入场的概率: ((MA8_prev > Low[1] && MA8_prev < High[1]) || (MA8_2p > Low[2] && MA8_2p < High[2]) || //波段的开始 - 在数据历史中不远于3个柱 (М1) (MA8_3p > Low[3] && MA8_3p < High[3])) && //相同 MA5_prev_m15 > L_prev_m15 && MA5_prev_m15 < H_prev_m15 && //波段的开始 - 在较高时段(М15)的前一个柱 //---减少在入场交易时缺乏明确定义的趋势有关的风险------- //在较低时段模拟烛形的方向: Close[2] < Open[2] && //在历史中的第二个柱是向下的方向 (М1) Close[1] < Open[1] && //前一个柱形也是向下的方向 (М1) //在较低时段中模拟移动平均的方向: MA5_cur < MA5_2p && MA60_cur < MA60_2p && //下降的 МА: 使用的周期数为5和60的移动平均 (М1) //在较低时段中模拟移动平均的继承: MA5_cur < MA8_cur && MA8_cur < MA13_cur && //在M1上形成三个移动平均构成的层次(斐波那契周期数:5,8,13), 这是下跌的间接迹象 //模拟当前价格相对于较低时段移动平均的位置: Bid < MA5_cur && Bid < MA8_cur && Bid < MA13_cur && Bid < MA60_cur && //当前价格在M1上超过了 МА (5,8,13,60), 这是下跌变化的间接迹象 //在较高时段中模拟烛形方向: C_prev_m15 < O_prev_m15 && //之前的烛形方向向下 (М15) //在较高时段模拟烛形方向: MA4_cur_m15 < MA4_2p_m15 && //之前烛形方向向下 (М15) //在较高时段模拟移动平均的方向: MA4_prev_m15 < MA8_prev_m15 && //在 M1 (周期数为4和8) 上的两个移动平均构成层次, 这是下跌变化的间接迹象 //模拟当前价格与较高时段移动平均的相对位置: Bid < MA4_cur_m15 && //当前价格低于 МА4 (М15), 这是下跌变化的间接迹象 Bid < MA24_cur_h1 && //当前价格低于 МА24 (МН1), 这是下跌变化的间接迹象 //模拟在较低时段当前烛形内部的微趋势,以及进场点: Bid < Open[0] && //在当前柱内部出现下跌变化 (М1) //模拟在较高时段之前的处理中有足够的活动: (O_prev_m15 - C_prev_m15) > (0.5*(H_prev_m15 - L_prev_m15)) && //烛形"体部"所占比例超过烛形幅度的 50% (前一个М15烛形) (C_prev_m15 - L_prev_m15) < (0.25*(H_prev_m15 - L_prev_m15)) && //修正深度低于烛形幅度的 25% (前一个 М15 烛形) L_prev_m15 < L_2p_m15 && //根据局部阻力水平有上涨趋势 (两个 М15 烛形) O_prev_m15 < H_prev_m15 && O_prev_m15 > L_prev_m15 && //具有相对于当前烛形开盘价的烛芯 (前一个 М15 烛形) //模拟在较低时段之前的处理中有足够的活动: (Open[1] - Close[1]) > (0.5*(High[1] - Low[1])) && //烛形“体部”所占比例超过烛形幅度的 50% (前一个 М1 烛形) (High[1] - Low[1]) > 70*Point && //之前烛形的幅度超过阈值 (排除明显的平盘) (Close[2] - Low[2]) < (0.25*(High[2] - Low[2])) && //修正深度限额低于烛形幅度的 20% ( М1 数据历史中的第二个烛形) Low[1] < Low[2] && //根据局部阻力水平有下跌趋势 (两个M1烛形) Open[1] < High[1] && Open[1] > Low[1] ) //相对当前烛形的开盘价出现烛芯 (前一个 М1 烛形) { //如果指定的入场卖出算法条件符合,就声称卖出入场订单: sl_sell = NormalizeDouble((Ask+StopLoss*Point),Digits); tp_sell = NormalizeDouble((Bid-TakeProfit*Point),Digits); numb = OrderSend(Symbol(),OP_SELL,Lots,Bid,3,sl_sell,tp_sell,"Reduce_risks",16384,0,Red); if(numb > 0) { if(OrderSelect(numb,SELECT_BY_TICKET,MODE_TRADES)) { Print("Sell entry : ",OrderOpenPrice()); } } else Print("开启卖出订单出错 : ",GetLastError()); } //--- 入场交易算法 (买入, 卖出) 在此结束 return; } //--- 检查开启的订单和金融资产的交易品种名称,准备关闭仓位: for(f=0; f < kol; f++) { if(!OrderSelect(f,SELECT_BY_POS,MODE_TRADES)) continue; if(OrderType()<=OP_SELL && //检查订单类型 OrderSymbol()==Symbol()) //检查交易品种 { if(OrderType()==OP_BUY) //如果订单是"买入", 转到关闭买入仓位: { //------关闭买入仓位的算法------------------------------------------------------------------------------------------------- //由于搜索开启仓位中价格最高值的模块-------------- //首先,定义当前点与入场点之间的距离: shift_buy = 0; if(Time_cur > OrderOpenTime() && OrderOpenTime() > 0) //如果当前时间比入场点远... { shift_buy = NormalizeDouble( ((Time_cur - OrderOpenTime() ) /60), 0 ); } //定义在 tfM1柱与入场点之间的距离 //现在,定义在入场交易后价格的最大值: Max_pos = 0; if(Time_cur > OrderOpenTime() && shift_buy > 0) { Max_pos = NormalizeDouble((High[iHighest(NULL,PERIOD_M1, MODE_HIGH ,(shift_buy + 1), 0)]), Digits);} //搜索仓位建立后价格最大值的模块到此结束-- //传送以关闭仓位 (OR 逻辑选项): if( //减少与入场后价格剧变相关的风险---------------------- (Bid < Open[0] && (Open[0] - Bid) >= 100*Point && (Time_cur - Time[0]) <= 20) //在任何区域内的入场条件如有价格崩溃 (参考点 - 当前的 M1 烛形开盘价) || (Bid < O_cur_m15 && (O_cur_m15 - Bid) >= 200*Point && (Time_cur - Time_cur_m15) <= 120) //在任何区域内的退出条件如有价格崩溃 (参考点 - 当前 M15 烛形开盘价) || ((Time_cur - OrderOpenTime()) > 60 && Close[1] < Open[1] && (Open[1] - Close[1]) >= 200*Point) //在任何区域内的退出条件如有价格崩溃(参考参数 - 前一个 M1 烛形幅度) || //减少入场交易后价格变化幅度不确定相关的风险-- //管理固定利润 (每个仓位): (Bid > OrderOpenPrice() && (Bid - OrderOpenPrice()) >= 100*Point) //在获利区域的退出条件 (影子获利) || //管理最大可接受的价格偏移 //与入场交易后当前最高价比较: (shift_buy >= 1 && //与入场点相差不少于一个柱 Time_cur > OrderOpenTime() && Max_pos > 0 && OrderOpenTime() > 0 && OrderOpenPrice() > 0 && //这是入场后的当前最大值 Max_pos > OrderOpenPrice() && //当前最大值在有利润区域 Bid < Max_pos && //有价格的反转变化 (Max_pos - Bid) >= 200*Point) //入场交易时距离当前最小值的反向偏移 || //管理预定义的风险限额 (每个仓位): (Bid < OrderOpenPrice() && (OrderOpenPrice() - Bid) >= 200*Point) //在亏损区域中的退出条件 (影子止损) || //管理预定义的风险限额 (对于全部存款): (AccountBalance() <= NormalizeDouble( (Depo_first*((100 - Percent_risk_depo)/100)), 0)) ) //如果在当前交易中超过了全部存款的风险限额 { if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet)) //如果处理了关闭算法,生成用于关闭买入仓位的订单 Print("关闭买入仓位出错 ",GetLastError()); //否则打印买入仓位关闭错误 return; } } else //否则,转到关闭卖出仓位: { //------卖出仓位关闭算法------------------------------------------------------------------------------------ //由于搜索开启仓位中价格最高值的模块-------------- //首先,定义当前点与入场点之间的距离: shift_sell = 0; if(Time_cur > OrderOpenTime() && OrderOpenTime() > 0) //如果当前时间比入场点远... { shift_sell = NormalizeDouble( ((Time_cur - OrderOpenTime() ) /60), 0 ); } //定义在M1中与入场点之间的距离柱数 //现在定义在入场交易后的价格最小值: Min_pos = 0; if(Time_cur > OrderOpenTime() && shift_sell > 0) { Min_pos = NormalizeDouble( (Low[iLowest(NULL,PERIOD_M1, MODE_LOW ,(shift_sell + 1), 0)]), Digits); } //搜索仓位建立后价格最大值的模块到此结束-- //传递用于关闭开启的卖出仓位 (或逻辑选项): if( //减少入场交易后价格崩溃相关的风险 ----------------- (Bid > Open[0] && (Bid - Open[0]) >= 100*Point && (Time_cur - Time[0]) <= 20) //在价格崩溃时的退出条件 (在任何区域) (参考点 - 当前 M1 柱开盘价) || (Bid > O_cur_m15 && (Bid - O_cur_m15) >= 200*Point && (Time_cur - Time_cur_m15) <= 120) //在价格崩溃时的退出条件 (在任何区域中) (参考点 - 当前 M15 柱形开盘价) || ((Time_cur - OrderOpenTime()) > 60 && Close[1] > Open[1] && (Close[1] - Open[1]) >= 200*Point) //在任何区域中的价格崩溃时的退出条件 (参考参数 - 前一个 M1 柱形的幅度) || //减少入场交易后价格变化幅度不确定相关的风险-- //管理固定利润 (每个仓位): (Bid < OrderOpenPrice() && (OrderOpenPrice()- Bid) >= 100*Point) //退出条件在利润区域内 (影子获利) || //管理最大可接受的价格偏移 //在进入市场后和当前最小值相比: (shift_sell >= 1 && //偏离入场点至少一个柱 Time_cur > OrderOpenTime() && Min_pos > 0 && OrderOpenTime() > 0 && OrderOpenPrice() > 0 && //入场后的当前最小值 Min_pos < OrderOpenPrice() && //当前最小值在利润区域之内 Bid > Min_pos && //有反转的价格变化 (Bid - Min_pos) >= 200*Point) //距离当前最小值的反向偏移,推出市场 || //管理预定义的风险限额 (每个仓位): (Bid > OrderOpenPrice() && (Bid - OrderOpenPrice()) >= 200*Point) //在亏损区域内的退出条件 (影子止损) || //管理预定义的风险限额 (对于全部存款): (AccountBalance() <= NormalizeDouble( (Depo_first*((100 - Percent_risk_depo)/100)), 0)) ) //如果在当前的交易中超过了针对整体存款的风险限额 { if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet)) //如果执行了关闭算法,生成卖出仓位关闭订单 Print("Error closing Sell position ",GetLastError()); //否者,打印卖出仓位关闭错误 return; } } } } //--- } //-----------------------------------------------------------------------------------------------------------
图 12. 考虑到一些所述风险的EA交易实例
EA 的代码结构考虑了上面所描述的一些风险,它也包含了相应的模块来减少它们。
这个 EA 交易在 М1 时段载入,并且在下面交易品种的历史数据中做了测试: EURUSD, USDCHF 和 USDJPY。
EURUSD 测试结果:
图 13. EURUSD 测试结果
当测试了一年半的时候,取得了正面的结果。
USDCHF 测试结果:
图 14. USDCHF 测试结果
当测试了一年半的时候,取得了正面的结果。但是,入场交易的数量还是不够。
USDJPY 测试结果:
图 15. USDJPY 测试结果
当测试了一年半的时候,取得了正面的结果。
现在, 评估每种风险的重要性,为此,我们使用下面的流程:
- 使用EA获得的净利润作为主参数;
- 通过在EA算法中(单独)禁用某个模块来确定对应风险类型的重要性,
- 交易结果越差,这种风险类型就越重要。
把 EURUSD 测试结果作为标准,定义了每个模块的相对影响。看一下下面的图:
图16. 使用之前描述的EA作为实例,风险类型的重要性
Fig. 16 注意:
- NetProfit 是一个轴,显示的是EA的净利润;
- А - "总和形式"的净利润 (所有减少风险的模块都包含在内);
- 1 - 用于减少与入场交易时波动性增加风险的模块被禁用;
- 2 - 用于减少与入场交易时出现阻力水平风险的模块被禁用;
- 3 - 用于减少与入场交易时进入超买/超卖区域风险的模块被禁用;
- 4 - 用于减少与入场交易时缺乏明确趋势风险的模块被禁用(该模块模拟在之前的处理中有足够的活动);
- 5 - 用于减少在入场交易时缺乏明确趋势风险的模块被禁用(该模块模拟烛形和移动平均的方向).
图中显示,最大亏损对应的是第4点,这里的结果比图中其他点要差几倍,所以,最重要的交易策略组件就是这个模块,它设置了过程的活动,
这就意味着最重要的风险 (至少对于这个给定的 EA 来说)是缺乏明确定义的趋势 (过程活动不足)。
结论
我们已经进行了主要风险的分类 — 与市场动态有关以及无关的。我们也描述了减少它们的方法,并且展示了一些实现它们的算法,后来,我们还使用了包含这些算法的 EA 进行了检验。另外,我们还在三个金融资产品种中测试了这个 EA — EURUSD, USDCHF 和 USDJPY。请注意,得到的结果是没有经过 EA 优化的,我是根据我个人的经验在模块中设置的价格水平阈值。
此外,还提供了一组移动平均值,以及根据日历周期将其包含到集合中的方法。在开发风险降低模块和EA作为一个整体时,我采用了这种方法。也提供了允许用户有所减少陷入超买/超卖区域的概率(基于波浪似的运动模拟)的方法。
在三个金融品种中取得了正面的结果,这一般证实了所描述的方法的正确性,无论是在风险分类方面,还是在减少风险的方法上,以及在确定考虑这些风险的交易系统的结构中。
进行的分析表明,不具有过程活动模拟的趋势跟踪交易系统是风险最大的。正是这一因素比其他因素在财务结果中的反映显得更加重要。
上面的 EA 的优点(以及所描述的构建交易策略的方法)是在输入和输出算法中没有包含传统的指标,只使用了烛形分析和移动平均(范围有限)。这大幅较少了优化的数量。在这里,它被减少到选择阈值级别,触发适当的模块,以及从可用的计算周期列表中选择MA周期(参见 "与不正确选择指标计算周期数有关的风险")。
所描述的方法的缺点是“过度过滤”的入场算法,因为可能有太多的风险(和适当的入场过滤器),结果是入场交易数量很有限。但是,这可以通过在多个金融资产品种做交易而部分减轻(在预先测试之后)。
这项工作的目的是创建一个简单的EA,以减少主要风险,同时具有新手交易者容易掌握的特点。当然,我们可以通过分析分形级别的算法来显著提高EA的效率。然而,这涉及到搜索分形(包括在循环中,这将显著地使代码复杂化)。我认为对新手分析师和交易者来说,最重要的一点是在进一步磨练他们的编程技巧之前,掌握交易系统的结构(根据市场动态参数)。
以这个EA为例,您将能够通过禁用某些模块或根据逻辑决定更改它们的集合来执行实验。
请注意!这个EA交易是一个简化的模拟版本,不应用于真实交易。
本文所述的减少市场风险的方法对于开发您自己的交易系统可能会有用。
本文中 MQL5 版本的EA交易在这里 - Reduce_risks.