概念
在创建EA事务之后,我们都会寻找内置的策略测试过程来选择最佳的参数。当选择这些参数时,我们运行EA,一旦发生任何重大变化,EA将停止,并使用策略测试过程一次又一次地优化。
我们可以指定重新优化决策和重新优化作为一个过程,而不自然中断其工作?
Quantum在其文章“MetaTrader 5客户机中的自适应交易系统及其应用”中提出了该问题的解决方案,该文章专门使用真实交易系统和几种(数量不限)虚拟交易策略来选择迄今为止利润最大的一种。策略。在超过固定列值之后,采用改变交易策略的决定。
我建议使用JOO中的“遗传算法”-非常简单!文中提出了遗传算法(GA)。让我们看看这种EA事务的实现(以下是为2011年自动交易锦标赛编写的EA)。
正在进行的工作
然后,我们需要定义EA交易应该做什么。首先,不言而喻,交易是采用选择的策略进行的。接下来,决定是否优化新的输入参数优化。其次,GA用于进一步优化。首先,让我们回顾一下最简单的重新优化——有一种策略,我们只选择新的参数。然后,我们将看看GA是否可以用来选择在变化的市场环境中的其他策略,如果是的话,如何进行。
此外,为了便于在适应度函数中模拟,我们决定只在一个工具上交易完成的列。将没有额外的职位和部分清算。对于那些喜欢使用固定止损以及利润和跟踪止损的人,请参阅MetaTrader 5策略测试程序价格变化生成算法,以在健身函数中实现止损和利润订单检查。我将扩展下面的成语:
在适应度函数中,我在测试程序中只模拟了一个叫做开放价格的测试模式(仅公开价格)。但是!这并不意味着这是唯一可行的测试程序模拟适应度函数。更谨慎的人可能希望使用每一个蜱模型适应度函数测试。为了不重复“每次价格变化”的作品或零件,我想提醒他们MetaQuotes开发的现有算法。换言之,在阅读本文之后,读者将能够在适应度函数中模拟“每滴答”模型,这是正确模拟适应度函数中的停止和利润的必要条件。
在继续讨论要点(策略实现)之前,让我们简要回顾一下新专栏的开放、仓库和仓库的技术性质以及辅助功能的实现。
//+------------------------------------------------------------------+ //| Define whether a new bar has opened | //+------------------------------------------------------------------+ bool isNewBars() { CopyTime(s,tf,0,1,curBT); TimeToStruct(curBT[0],curT); if(tf==PERIOD_M1|| tf==PERIOD_M2|| tf==PERIOD_M3|| tf==PERIOD_M4|| tf==PERIOD_M5|| tf==PERIOD_M6|| tf==PERIOD_M10|| tf==PERIOD_M12|| tf==PERIOD_M15|| tf==PERIOD_M20|| tf==PERIOD_M30) if(curT.min!=prevT.min) { prevBT[0]=curBT[0]; TimeToStruct(prevBT[0],prevT); return(true); }; if(tf==PERIOD_H1|| tf==PERIOD_H2|| tf==PERIOD_H3|| tf==PERIOD_H4|| tf==PERIOD_H6|| tf==PERIOD_H8|| tf==PERIOD_M12) if(curT.hour!=prevT.hour) { prevBT[0]=curBT[0]; TimeToStruct(prevBT[0],prevT); return(true); }; if(tf==PERIOD_D1|| tf==PERIOD_W1) if(curT.day!=prevT.day) { prevBT[0]=curBT[0]; TimeToStruct(prevBT[0],prevT); return(true); }; if(tf==PERIOD_MN1) if(curT.mon!=prevT.mon) { prevBT[0]=curBT[0]; TimeToStruct(prevBT[0],prevT); return(true); }; return(false); } //+------------------------------------------------------------------+ //| ClosePosition | //+------------------------------------------------------------------+ void ClosePosition() { request.action=TRADE_ACTION_DEAL; request.symbol=PositionGetSymbol(0); if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) request.type=ORDER_TYPE_SELL; else request.type=ORDER_TYPE_BUY; request.type_filling=ORDER_FILLING_FOK; if(SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST|| SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT) { request.sl=NULL; request.tp=NULL; request.deviation=100; } while(PositionsTotal()>0) { request.volume=NormalizeDouble(MathMin(PositionGetDouble(POSITION_VOLUME),SymbolInfoDouble(PositionGetSymbol(0),SYMBOL_VOLUME_MAX)),2); if(SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST|| SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT) { if(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID); else request.price=SymbolInfoDouble(s,SYMBOL_ASK); } OrderSend(request,result); Sleep(10000); } } //+------------------------------------------------------------------+ //| OpenPosition | //+------------------------------------------------------------------+ void OpenPosition() { double vol; request.action=TRADE_ACTION_DEAL; request.symbol=s; request.type_filling=ORDER_FILLING_FOK; if(SymbolInfoInteger(s,SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST|| SymbolInfoInteger(s,SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT) { request.sl=NULL; request.tp=NULL; request.deviation=100; } vol=MathFloor(AccountInfoDouble(ACCOUNT_FREEMARGIN)*optF*AccountInfoInteger(ACCOUNT_LEVERAGE) /(SymbolInfoDouble(s,SYMBOL_TRADE_CONTRACT_SIZE)*SymbolInfoDouble(s,SYMBOL_VOLUME_STEP)))*SymbolInfoDouble(s,SYMBOL_VOLUME_STEP); vol=MathMax(vol,SymbolInfoDouble(s,SYMBOL_VOLUME_MIN)); vol=MathMin(vol,GetPossibleLots()*0.95); if(SymbolInfoDouble(s,SYMBOL_VOLUME_LIMIT)!=0) vol=NormalizeDouble(MathMin(vol,SymbolInfoDouble(s,SYMBOL_VOLUME_LIMIT)),2); request.volume=NormalizeDouble(MathMin(vol,SymbolInfoDouble(s,SYMBOL_VOLUME_MAX)),2); while(PositionSelect(s)==false) { if(SymbolInfoInteger(s,SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST|| SymbolInfoInteger(s,SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT) { if(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID); else request.price=SymbolInfoDouble(s,SYMBOL_ASK); } OrderSend(request,result); Sleep(10000); PositionSelect(s); } while(PositionGetDouble(POSITION_VOLUME)<vol) { request.volume=NormalizeDouble(MathMin(vol-PositionGetDouble(POSITION_VOLUME),SymbolInfoDouble(s,SYMBOL_VOLUME_MAX)),2); if(SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST|| SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT) { if(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID); else request.price=SymbolInfoDouble(s,SYMBOL_ASK); } OrderSend(request,result); Sleep(10000); PositionSelect(s); } } //+------------------------------------------------------------------+
仔细考虑之后,您可能会注意到仓库函数中的三个重要参数:s和optF变量,以及GetPossibleLots()函数调用:
- S交易工具,GA优化的变量之一,
- OPTF-交易的边际部分(GA优化的另一变量);
- GETIMABLILTETS()函数返回用于交易的保证金部分:
//+------------------------------------------------------------------+ //| GetPossibleLots | //+------------------------------------------------------------------+ double GetPossibleLots() { request.volume=1.0; if(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID); else request.price=SymbolInfoDouble(s,SYMBOL_ASK); OrderCheck(request,check); return(NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)/check.margin,2)); }
为了稍微扰乱叙述,让我们介绍所有EA在第二阶段中都具有并且非常重要的两个其他功能:
//+------------------------------------------------------------------+ //| InitRelDD | //+------------------------------------------------------------------+ void InitRelDD() { ulong DealTicket; double curBalance; prevBT[0]=D'2000.01.01 00:00:00'; TimeToStruct(prevBT[0],prevT); curBalance=AccountInfoDouble(ACCOUNT_BALANCE); maxBalance=curBalance; HistorySelect(D'2000.01.01 00:00:00',TimeCurrent()); for(int i=HistoryDealsTotal();i>0;i--) { DealTicket=HistoryDealGetTicket(i); curBalance=curBalance+HistoryDealGetDouble(DealTicket,DEAL_PROFIT); if(curBalance>maxBalance) maxBalance=curBalance; } } //+------------------------------------------------------------------+ //| GetRelDD | //+------------------------------------------------------------------+ double GetRelDD() { if(AccountInfoDouble(ACCOUNT_BALANCE)>maxBalance) maxBalance=AccountInfoDouble(ACCOUNT_BALANCE); return((maxBalance-AccountInfoDouble(ACCOUNT_BALANCE))/maxBalance); }
我们在这里看到什么?第一函数确定最大账户余额值,第二函数计算账户的相对流动损失。它们的特点将被列在解释的第二阶段。
移到 EA。因为我们仅仅是初学者,我们不会获得一个从中选择策略的 EA,但会严格实施两个具有以下策略的 EA:
- 交叉使用移动平均(黄金交叉-我们购买金融工具,死亡交叉-我们出售);
- 另一个是一个简单的神经网络,它在过去五个交易时段内接受[0.1 ]范围内的价格变化。
在该算法中,可以通过以下示例来说明自优化EA事务的工作:
- 初始化EA事务中使用的变量:定义和初始化索引缓存,或者建立神经网络拓扑(一层中的层数/神经元数;以简单的神经网络为例,其中所有层的神经元数相同),设置w时间框架。此外,这也许是最重要的步骤——我们称之为遗传优化函数,它求解最重要的函数——适应度函数(以下简称FF)。重要注释!每一个交易策略都有一个新的FF,也就是说,每次它都会重新创建一个新的FF。一个移动平均的FF与两个移动平均的FF完全不同,与神经网络FF完全不同。我的EA事务中的FF性能结果是最大余额,条件是相对损失不超过作为外部变量设置的阈值(在本例中为0.5)。换句话说,如果下一个GA运行产生100000的平衡,相对平衡损失是-0.6,那么FF=0。亲爱的读者,在你的情况下,FF的结果可能会导致完全不同的标准。收集遗传算法的性能结果:对于移动平均的交集,这些显然是移动平均周期,对于神经网络,突触权重,它们的共同结果(以及我的其他EA的结果)是金融工具,要进行交易直到下一次优化,以及OPTF,这是我们已经熟悉的。用于交易的保证金的一部分。这取决于你把优化参数添加到你的FF中,比如时间框架或其他参数。初始化的最后一步是找出最大账户余额值。为什么重要?因为这是进一步优化的起点。重要注释!重新优化决策过程:一旦相对平衡损失达到作为外部变量(在本例中为0.2)设置的临界值,我们就需要重新优化。为了在达到临界损失时不允许EA对每一列进行重新优化,最大平衡值被当前值替换。亲爱的读者,你可能有完全不同的标准来实现再优化。
- 正在进行的交易。
- 在每次闭合时,我们检查平衡损失是否达到临界值。如果我们达到临界值,我们运行GA并收集其性能结果(即,重新优化)。
- 我们要么等待外汇管理局局长来电,要求不要毁灭世界,要么(更有可能)停止亏损、离开、增加利润或者等待救护车。
下面请查找使用移动平均策略的EA编程实现(提供了源代码)和使用神经网络的EA的编程实现,所有这些都作为源代码提供。
该代码是根据GPL许可证的条款和条件提供的。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { tf=Period(); //---for bar-to-bar test... prevBT[0]=D'2001.01.01'; //---... long ago TimeToStruct(prevBT[0],prevT); //--- historical depth (should be set since the optimisation is based on historical data) depth=10000; //--- copies at a time (should be set since the optimisation is based on historical data) count=2; ArrayResize(LongBuffer,count); ArrayResize(ShortBuffer,count); ArrayInitialize(LongBuffer,0); ArrayInitialize(ShortBuffer,0); //--- calling the neural network genetic optimisation function GA(); //--- getting the optimised neural network parameters and other variables GetTrainResults(); //--- getting the account drawdown InitRelDD(); return(0); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if(isNewBars()==true) { bool trig=false; CopyBuffer(MAshort,0,0,count,ShortBuffer); CopyBuffer(MAlong,0,0,count,LongBuffer); if(LongBuffer[0]>LongBuffer[1] && ShortBuffer[0]>LongBuffer[0] && ShortBuffer[1]<LongBuffer[1]) { if(PositionsTotal()>0) { if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) { ClosePosition(); trig=true; } } } if(LongBuffer[0]<LongBuffer[1] && ShortBuffer[0]<LongBuffer[0] && ShortBuffer[1]>LongBuffer[1]) { if(PositionsTotal()>0) { if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL) { ClosePosition(); trig=true; } } } if(trig==true) { //--- if the account drawdown has exceeded the allowable value: if(GetRelDD()>maxDD) { //--- calling the neural network genetic optimisation function GA(); //--- getting the optimised neural network parameters and other variables GetTrainResults(); //--- readings of the drawdown will from now on be based on the current balance instead of the maximum balance maxBalance=AccountInfoDouble(ACCOUNT_BALANCE); } } CopyBuffer(MAshort,0,0,count,ShortBuffer); CopyBuffer(MAlong,0,0,count,LongBuffer); if(LongBuffer[0]>LongBuffer[1] && ShortBuffer[0]>LongBuffer[0] && ShortBuffer[1]<LongBuffer[1]) { request.type=ORDER_TYPE_SELL; OpenPosition(); } if(LongBuffer[0]<LongBuffer[1] && ShortBuffer[0]<LongBuffer[0] && ShortBuffer[1]>LongBuffer[1]) { request.type=ORDER_TYPE_BUY; OpenPosition(); } }; } //+------------------------------------------------------------------+ //| Preparing and calling the genetic optimizer | //+------------------------------------------------------------------+ void GA() { //--- number of genes (equal to the number of optimised variables), //--- all of them should be specified in the FitnessFunction()) GeneCount =OptParamCount+2; //--- number of chromosomes in a colony ChromosomeCount=GeneCount*11; //--- minimum search range RangeMinimum =0.0; //--- maximum search range RangeMaximum =1.0; //--- search pitch Precision =0.0001; //--- 1 is a minimum, anything else is a maximum OptimizeMethod =2; ArrayResize(Chromosome,GeneCount+1); ArrayInitialize(Chromosome,0); //--- number of epochs without any improvement Epoch =100; //--- ratio of replication, natural mutation, artificial mutation, gene borrowing, //--- crossingover, interval boundary displacement ratio, every gene mutation probabilty, % UGA(100.0,1.0,1.0,1.0,1.0,0.5,1.0); } //+------------------------------------------------------------------+ //| Fitness function for neural network genetic optimizer: | //| selecting a pair, optF, synapse weights; | //| anything can be optimised but it is necessary | //| to carefully monitor the number of genes | //+------------------------------------------------------------------+ void FitnessFunction(int chromos) { int b; //--- is there an open position? bool trig=false; //--- direction of an open position string dir=""; //--- opening price double OpenPrice=0; //--- intermediary between a gene colony and optimised parameters int z; //--- current balance double t=cap; //--- maximum balance double maxt=t; //--- absolute drawdown double aDD=0; //--- relative drawdown double rDD=0.000001; //--- fitness function proper double ff=0; //--- GA is selecting a pair z=(int)MathRound(Colony[GeneCount-1][chromos]*12); switch(z) { case 0: {s="AUDUSD"; break;}; case 1: {s="AUDUSD"; break;}; case 2: {s="EURAUD"; break;}; case 3: {s="EURCHF"; break;}; case 4: {s="EURGBP"; break;}; case 5: {s="EURJPY"; break;}; case 6: {s="EURUSD"; break;}; case 7: {s="GBPCHF"; break;}; case 8: {s="GBPJPY"; break;}; case 9: {s="GBPUSD"; break;}; case 10: {s="USDCAD"; break;}; case 11: {s="USDCHF"; break;}; case 12: {s="USDJPY"; break;}; default: {s="EURUSD"; break;}; } MAshort=iMA(s,tf,(int)MathRound(Colony[1][chromos]*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN); MAlong =iMA(s,tf,(int)MathRound(Colony[2][chromos]*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN); dig=MathPow(10.0,(double)SymbolInfoInteger(s,SYMBOL_DIGITS)); //--- GA is selecting the optimal F optF=Colony[GeneCount][chromos]; leverage=AccountInfoInteger(ACCOUNT_LEVERAGE); contractSize=SymbolInfoDouble(s,SYMBOL_TRADE_CONTRACT_SIZE); b=MathMin(Bars(s,tf)-1-count-MaxMAPeriod,depth); //--- for a neural network using historical data - where the data is copied from for(from=b;from>=1;from--) { CopyBuffer(MAshort,0,from,count,ShortBuffer); CopyBuffer(MAlong,0,from,count,LongBuffer); if(LongBuffer[0]>LongBuffer[1] && ShortBuffer[0]>LongBuffer[0] && ShortBuffer[1]<LongBuffer[1]) { if(trig==false) { CopyOpen(s,tf,from,count,o); OpenPrice=o[1]; dir="SELL"; trig=true; } else { if(dir=="BUY") { CopyOpen(s,tf,from,count,o); if(t>0) t=t+t*optF*leverage*(o[1]-OpenPrice)*dig/contractSize; else t=0; if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t; if((maxt>0) && (aDD/maxt>rDD)) rDD=aDD/maxt; OpenPrice=o[1]; dir="SELL"; trig=true; } } } if(LongBuffer[0]<LongBuffer[1] && ShortBuffer[0]<LongBuffer[0] && ShortBuffer[1]>LongBuffer[1]) { if(trig==false) { CopyOpen(s,tf,from,count,o); OpenPrice=o[1]; dir="BUY"; trig=true; } else { if(dir=="SELL") { CopyOpen(s,tf,from,count,o); if(t>0) t=t+t*optF*leverage*(OpenPrice-o[1])*dig/contractSize; else t=0; if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t; if((maxt>0) && (aDD/maxt>rDD)) rDD=aDD/maxt; OpenPrice=o[1]; dir="BUY"; trig=true; } } } } if(rDD<=trainDD) ff=t; else ff=0.0; AmountStartsFF++; Colony[0][chromos]=ff; } //+---------------------------------------------------------------------+ //| getting the optimized neural network parameters and other variables | //| should always be equal to the number of genes | //+---------------------------------------------------------------------+ void GetTrainResults() { //--- intermediary between a gene colony and optimised parameters int z; MAshort=iMA(s,tf,(int)MathRound(Chromosome[1]*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN); MAlong =iMA(s,tf,(int)MathRound(Chromosome[2]*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN); CopyBuffer(MAshort,0,from,count,ShortBuffer); CopyBuffer(MAlong,0,from,count,LongBuffer); //--- save the best pair z=(int)MathRound(Chromosome[GeneCount-1]*12); switch(z) { case 0: {s="AUDUSD"; break;}; case 1: {s="AUDUSD"; break;}; case 2: {s="EURAUD"; break;}; case 3: {s="EURCHF"; break;}; case 4: {s="EURGBP"; break;}; case 5: {s="EURJPY"; break;}; case 6: {s="EURUSD"; break;}; case 7: {s="GBPCHF"; break;}; case 8: {s="GBPJPY"; break;}; case 9: {s="GBPUSD"; break;}; case 10: {s="USDCAD"; break;}; case 11: {s="USDCHF"; break;}; case 12: {s="USDJPY"; break;}; default: {s="EURUSD"; break;}; } //--- saving the best optimal F optF=Chromosome[GeneCount]; } //+------------------------------------------------------------------+
让我们来看看该算法的主要功能适应度函数。
自优化EA交易的整个思想基于在适应度函数(如在标准MetaQuotes测试程序中)的某个时间段(例如10000支柱的历史)内对交易过程的模拟,该适应度函数接收来自遗传算法(GA函数)。如果算法是基于移动平均线的交点,优化变量包括:
- 工具(外汇中的货币对);是的,它是一个典型的多货币EA事务,遗传算法选择一个工具(因为代码来自为比赛编写的EA事务,它有与比赛货币相对应的货币对;一般来说,它可以是兄弟的任何工具报价单)。注意,
:不幸的是,EA事务在测试模式下无法从MarketWatch窗口获得货币对的列表(由于MetaQuotes用户,我们在这里澄清了这一点——不可能!)因此,如果希望在测试程序中分别运行外汇和股票的EA事务,请在FF和GetTrain.()函数中指定自己的工具。
- 用于交易的保证金部分;
- 两个移动平均数的周期。
下面的示例说明了用于测试的EA事务的情况。
从MalkWistWin窗口提供的工具列表可以大大简化实际交易代码。
为此,在带有注释的FF和GetTrain.()函数中“/-GA选择一对”(GA选择一对货币)和“/-保存最佳货币对”(保存最佳货币对),它们被简单地写成:
//--- GA is selecting a pair z=(int)MathRound(Colony[GeneCount-1][chromos]*(SymbolsTotal(true)-1)); s=SymbolName(z,true);
因此,在FF开头,我们指定并初始化变量,以在必要时模拟基于历史的事务。在下一阶段,我们将从遗传算法中收集不同的优化变量值,如“optF=Colony[GeneCount][chromos]行,并将部分边际值从GA传递到FF。
我们进一步检查历史上可用的列的数量,从第1000列开始,或者在接收模拟的只开放价格(只开放价格)模型中的报价的过程中从第一列开始,并且做出交易决策:
- 将移动平均值复制到缓存;
- 检查死亡是否交叉。
- 如果存在死亡交叉点,并且没有开放位置(如果(trig==false)-创建虚拟销售位置(只需记住建筑物的价格和方向);
- 如果存在死亡交叉,并且存在不公平的购买位置(如果(dir=“BUY”)-支柱的开盘价并注意三条非常重要的线,如下:
- 模拟收盘和结算变化:当前余额增加当前余额价值,乘以待交易的保证金部分,乘以开盘和结盘价格之间的差异,乘以价格利润点价格(近似);
- 检查当前余额是否已达到交易模拟历史中的最大值;如果没有,计算资金的最大余额损失;
- 将先前计算的资本损失转换为相对平衡损失;
- 创建一个虚拟的销售位置(只记得仓库的价格和方向)。
- 对金交叉进行同样的检查和计算。
在遍历整个可用历史并模拟虚拟事务之后,计算最终的FF值:如果计算的相对余额损失小于测试的损失集,则FF=余额,否则FF=0。遗传算法的目的是最大化适应度函数。
最后,在给出工具、边际部分和移动平均周期后,遗传算法将找到具有最小相对损失(由用户设置)的最大平衡值。
总结
这里有一个简短的总结:创建自我训练的EA事务很容易,但是困难在于找出要输入什么(重要的是思想,实现只是一个技术问题)。
悲观主义者会问:“这有用吗?”我的回答是有用的;对于乐观主义者来说,这不是普遍的圣杯。
所提出的方法与量子方法的根本区别是什么?这可以通过使用移动平均值来比较EA交易来最好地说明。
- 在自适应训练系统中,移动平均的周期应该在编译和编码之前严格确定,并且只在有限的情况下才行。在遗传优化EA交易中,我们在编译之前没有做出任何决定。这个决定是由遗传算法决定的,病例数仅限于判断。
- 适应性交易系统中的虚拟交易是支柱对支柱的;很少在遗传优化EA交易中——并且只有当重新优化条件发生时。在自适应交易系统中,受策略、参数和工具数量的增加影响的计算机性能可能是限制因素。
附录
下面是使用2010年1月1日在测试程序中的每日图表数据运行神经网络而不进行任何优化的结果。
策略测试程序报告 | ||||||||||||
Meta卫星演示(构建523) | ||||||||||||
nbsp; | ||||||||||||
EA交易: | 一个例子 | |||||||||||
交易品种: | 欧元兑美元 | |||||||||||
周期: | 每日(2010.01.01-2011.0930) | |||||||||||
输入参数: | TRAILDD=0.9 | |||||||||||
nbsp; | MAXDD=0.1 | |||||||||||
代理: | 阿尔巴里新西兰有限公司 | |||||||||||
货币: | 美元 | |||||||||||
初始存款: | 一万 | |||||||||||
杠杆比率: | 1:100 | |||||||||||
结果 | ||||||||||||
历史质量: | 100% | |||||||||||
列数: | 四百五十四 | 价格变动: | 二百五十五万四千八百七十九 | |||||||||
净利润总额: | 9—94.49 | 毛利人: | 二万九千四百零一点零九 | 脱发: | 38—495.58 | |||||||
利润系数: | 零点七六 | 估计利润: | -20.53 | 保证金水平: | 732.30% | |||||||
回收系数: | -0.76 | 尖锐比率: | -0.06 | 测试器结果: | 零 | |||||||
nbsp; | ||||||||||||
平衡损失: | ||||||||||||
绝对平衡损失: | 九千一百零二点五六 | 最大平衡损失: | 11464.70(92.74%) | 相对平衡损失: | 92.74%(11464.70) | |||||||
市值损失: | ||||||||||||
绝对市值损失: | 九千一百七十六点九九 | 最大市值损失: | 11904(93.53%) | 相对市场损失: | 93.53%(11904) | |||||||
nbsp; | ||||||||||||
总交易时间: | 四百四十三 | 短期交易数量(利润%): | 7(14.29%) | 长期交易数量(利润%): | 436(53.44%) | |||||||
交易总数: | 八百八十六 | 有利可图交易的数量(总交易的百分比): | 234(52.82%) | 损失交易的数量(总交易的百分比): | 209(47.18%) | |||||||
nbsp; | 利润最大化交易: | 一千零九十五点五七 | 最大损失交易: | 1—438.85 | ||||||||
nbsp; | 平均利润交易: | 一百二十五点六五 | 平均亏损交易: | -184.19 | ||||||||
nbsp; | 最大持续利润(利润量): | 8(397.45) | 连续损失的最大数目(损失量): | 8(-1 1) | ||||||||
nbsp; | 最大连续产量(利润频率): | 1095.57(1) | 最大持续损失(损失时间): | – 3 433.21(6) | ||||||||
nbsp; | 连续利润的平均数: | 二 | 连续亏损的平均数: | 二 |
下面是三种可供选择的优化方案:
第一种…
时间 | 迪尔 | 交易品种 | 类型 | 方向 | 交易量 | 价格 | 秩序 | 库存费用 | 利润 | 平衡 |
2010.01.01 00 | 一 | nbsp; | 平衡 | nbsp; | nbsp; | nbsp; | nbsp; | 零 | 一万 | 一万 |
2010.01.04 00 | 二 | 澳元兑美元 | 购买 | 进入 | 零点九零 | 零点八九九七七 | 二 | 零 | 零 | 一万 |
2010.01.05 00 | 三 | 澳元兑美元 | 卖 | 由于 | 零点九零 | 零点九一一八八 | 三 | 五点六七 | 一千零八十九点九零 | 一万一千零九十五点五七 |
2010.01.05 00 | 四 | 澳元兑美元 | 购买 | 进入 | 零点九九 | 零点九一二二零 | 四 | 零 | 零 | 一万一千零九十五点五七 |
2010.01.06 00 | 五 | 澳元兑美元 | 卖 | 由于 | 零点九九 | 零点九一一五七 | 五 | 六点二四 | -62.37 | 一万一千零三十九点四四 |
2010.01.06 00 | 六 | 澳元兑美元 | 购买 | 进入 | 零点九九 | 零点九一一九零 | 六 | 零 | 零 | 一万一千零三十九点四四 |
2010.01.07 00 | 七 | 澳元兑美元 | 卖 | 由于 | 零点九九 | 零点九一九二四 | 七 | 十八点七一 | 七百二十六点六六 | 一万一千七百八十四点八一 |
第二类…
时间 | 迪尔 | 交易品种 | 类型 | 方向 | 交易量 | 价格 | 秩序 | 服务费 | 库存费用 | 利润 | 平衡 |
2010.05.19:00 | 一百八十九 | 澳元兑美元 | 卖 | 由于 | 零点三六 | 零点八六一一零 | 一百八十九 | 零 | 二点二七 | -595.44 | 四千二百二十一点三零 |
2010.05.19:00 | 一百九十 | 欧劳 | 卖 | 进入 | 零点三零 | 一点四一二八零 | 一百九十 | 零 | 零 | 零 | 四千二百二十一点三零 |
2010.05.20:00 | 一百九十一 | 欧劳 | 购买 | 由于 | 零点三零 | 一点四六二零七 | 一百九十一 | 零 | 七点四三 | 1—273.26 | 二千九百五十五点四七 |
2010.05.20:00 | 一百九十二 | 澳元兑美元 | 购买 | 进入 | 零点二一 | 零点八四九八三 | 一百九十二 | 零 | 零 | 零 | 二千九百五十五点四七 |
第三种
时间 | 迪尔 | 交易品种 | 类型 | 方向 | 交易量 | 价格 | 秩序 | 库存费用 | 利润 | 平衡 |
2010.06:16:00 | 二百三十 | 银杏叶提取物 | 购买 | 进入 | 零点零六 | 一点六七八七二 | 二百三十 | 零 | 零 | 二千一百二十八点八零 |
2010.0617:00 | 二百三十一 | 银杏叶提取物 | 卖 | 由于 | 零点零六 | 一点六六五四七 | 二百三十一 | 零点一三 | -70.25 | 二千零五十八点六八 |
2010.0617:00 | 二百三十二 | 银杏叶提取物 | 购买 | 进入 | 零点零六 | 一点六六六三五 | 二百三十二 | 零 | 零 | 二千零五十八点六八 |
2010.061800 | 二百三十三 | 银杏叶提取物 | 卖 | 由于 | 零点零六 | 一点六四七零五 | 二百三十三 | 零点零四 | -104.14 | 一千九百五十四点五八 |
2010.061800 | 二百三十四 | 澳元兑美元 | 购买 | 进入 | 零点零九 | 零点八六七四一 | 二百三十四 | 零 | 零 | 一千九百五十四点五八 |
2010.0621:00 | 二百三十五 | 澳元兑美元 | 卖 | 由于 | 零点零九 | 零点八七一八四 | 二百三十五 | 零点五七 | 三十九点87 | 一千九百九十五点零二 |
2010.0621:00 | 二百三十六 | 澳元兑美元 | 购买 | 进入 | 零点零九 | 零点八八一零五 | 二百三十六 | 零 | 零 | 一千九百九十五点零二 |
2010.0622:00 | 二百三十七 | 澳元兑美元 | 卖 | 由于 | 零点零九 | 零点八七六零六 | 二百三十七 | 零点五七 | -44.91 | 一千九百五十点六八 |
2010.0622:00 | 二百三十八 | 澳元兑美元 | 购买 | 进入 | 零点零九 | 零点八七六三七 | 二百三十八 | 零 | 零 | 一千九百五十点六八 |
2010.0623 00 | 二百三十九 | 澳元兑美元 | 卖 | 由于 | 零点零九 | 零点八七一四零 | 二百三十九 | 零点五七 | -44.73. | 一千九百零六点五二 |
2010.0623 00 | 二百四十 | 澳元兑美元 | 购买 | 进入 | 零点零八 | 零点八七一九七 | 二百四十 | 零 | 零 | 一千九百零六点五二 |
2010.062400 | 二百四十一 | 澳元兑美元 | 卖 | 由于 | 零点零八 | 零点八七三八五 | 二百四十一 | 一点五一 | 十五点零四 | 一千九百二十三点零七 |
2010.062400 | 二百四十二 | 澳元兑美元 | 购买 | 进入 | 零点零八 | 零点八七四一三 | 二百四十二 | 零 | 零 | 一千九百二十三点零七 |
2010.062500 | 二百四十三 | 澳元兑美元 | 卖 | 由于 | 零点零八 | 零点八六六三二 | 二百四十三 | 零点五零 | -62.48 | 一千八百六十一点零九 |
2010.062500 | 二百四十四 | 澳元兑美元 | 购买 | 进入 | 零点零八 | 零点八六六六三 | 二百四十四 | 零 | 零 | 一千八百六十一点零九 |
2010.0628 | 二百四十五 | 澳元兑美元 | 卖 | 由于 | 零点零八 | 零点八七三七五 | 二百四十五 | 零点五零 | 五十六点96 | 一千九百一十八点五五 |
2010.0628 | 二百四十六 | 澳元兑美元 | 购买 | 进入 | 零点零八 | 零点八七四一五 | 二百四十六 | 零 | 零 | 一千九百一十八点五五 |
2010.062.00 | 二百四十七 | 澳元兑美元 | 卖 | 由于 | 零点零八 | 零点八七一四零 | 二百四十七 | 零点五零 | -22.00 | 一千八百九十七点零五 |
2010.062.00 | 二百四十八 | 澳元兑美元 | 购买 | 进入 | 零点零八 | 零点八七一七三 | 二百四十八 | 零 | 零 | 一千八百九十七点零五 |
2010.07.01 | 二百四十九 | 澳元兑美元 | 卖 | 由于 | 零点零八 | 零点八四零五三 | 二百四十九 | 二点零一 | -24.60 | 一千六百四十九点四六 |
2010.07.01 | 二百五十 | 尤金 | 卖 | 进入 | 零点零七 | 零点八一八四一 | 二百五十 | 零 | 零 | 一千六百四十九点四六 |
2010.07.02 | 二百五十一 | 尤金 | 购买 | 由于 | 零点零七 | 零点八二五三五 | 二百五十一 | -0.04 | -73.68 | 一千五百七十五点七三 |
2010.07.02 | 二百五十二 | 尤金 | 卖 | 进入 | 零点零七 | 零点八二四九八 | 二百五十二 | 零 | 零 | 一千五百七十五点七三 |
2010.07.05 | 二百五十三 | 尤金 | 购买 | 由于 | 零点零七 | 零点八二六七六 | 二百五十三 | -0.04 | -18.96 | 一千五百五十六点七六 |
2010.07.05 | 二百五十四 | 尤金 | 卖 | 进入 | 零点零六 | 零点八二六零四 | 二百五十四 | 零 | 零 | 一千五百五十六点七六 |
2010.07.06 | 二百五十五 | 尤金 | 购买 | 由于 | 零点零六 | 零点八二八六二 | 二百五十五 | -0.04 | -23.43 | 一千五百三十三点二九 |
附录:作为作业:不仅要选择系统的参数,还要选择在某个时间最适合市场的系统(提示-从系统库中选择)。
本文是由Meta卫星软件公司在HTTPSE//www. MQL5.COM/RU/TUNESS/334中从俄语原文
中翻译而来的。
MyFxtop迈投(www.myfxtop.com)-靠谱的外汇跟单社区,免费跟随高手做交易!
免责声明:本文系转载自网络,如有侵犯,请联系我们立即删除,另:本文仅代表作者个人观点,与迈投财经无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。