在创建 EA 交易之后,我们都求助内置的策略测试程序来选择最佳参数。在选择这些参数时,我们运行 EA,并且一旦出现任何重大变化,则 EA 将会停止,并且一次又一次地使用策略测试程序进行优化。
我们能够将再优化决策和再优化作为一个进程分配给 EA 而不需要自然地中断其工作吗?
Quantum 在其《《自适应交易系统以及它们在 MetaTrader 5 客户端中的运用》一文中提出了这个问题的一个解决方案,专门致力于使用真实交易系统以及几个(在数量上没有限制)虚拟交易策略,从中选择一个目前为止具有最大盈利的策略。在超过某个固定的柱值之后,更改交易策略的决定被采纳。
我建议使用 joo 在《《遗传算法 - 很简单!》一文中提出的遗传算法 (GA) 代码。让我们看一看此类 EA 交易的实施(以下例子中的一个是为参加 2011 年自动交易锦标赛而写的 EA)。
那么,我们需要定义 EA 交易应能够做什么。首先,不言而喻的是使用选定的策略进行交易。其次,做出决定:是否应该再优化(执行输入参数的新优化)。再其次,利用 GA 进行再优化。首先,我们回顾一下最简单的再优化 - 有一个策略,并且我们只选择新的参数。然后,我们将看看是否能够利用 GA 在变化后的市场环境中选择其他策略,以及如果能够,如何进行。
此外,为了有利于适应度函数中的模拟,我们决定在一个工具上仅交易已完成柱。将不会有添加仓位和部分平仓。对于那些喜欢使用固定止损和获利以及跟踪止损的人,请参阅《MetaTrader 5 策略测试程序中的价格变动生成算法》一文,以在适应度函数中实施止损和获利订单检查。我将展开下面的习语:
在适应度函数中,我模拟了一种测试模式,这种模式在测试程序中被称为 "Open Prices Only"(仅开盘价)。但是!这并不意味着这是适应度函数中唯一可能的测试过程模拟。更加小心谨慎的人可能希望使用 "Every Tick"(每一价格变动)模式实施适应度函数测试。为了不重复劳动或拼凑“每一价格变动”,我愿意提醒他们注意 MetaQuotes 开发的现有算法。换言之,读过本文之后,读者将能够在适应度函数中模拟 "Every Tick"(每一价格变动)模式,这是在适应度函数中正确模拟止损和获利的必要条件。
在继续要点(策略实施)之前,让我们简短地回顾一下定义新柱的开盘以及建仓和平仓的技术性和实施辅助函数。
//+------------------------------------------------------------------+ //| 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() 函数调用:
//+------------------------------------------------------------------+ //| 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 交易使用的变量的初始化:定义和初始化指标缓存,或设置神经网络拓扑结构(层数/一层中的神经元数量;以一个简单的神经网络为例,其中神经元的数量在所有层中都是相同的),设置工作时间框架。此外,很可能是最重要的步骤 - 我们调用遗传优化函数,该函数解决最重要的函数 - 适应度函数(以下简称为 FF)。
重要须知!每一个交易策略有一个新的 FF,即每一次都会重新创建一个新的 FF。针对一条移动平均线的 FF 与针对两条移动平均线的 FF 完全不同,并且与神经网络 FF 完全不同。
我的 EA 交易中的 FF 性能结果是最大余额,前提是相对亏损未超过作为外部变量设置的临界值(在我们的例子中为 0.5)。换言之,如果下一次 GA 运行得出 100,000 的余额,而相对余额亏损为 -0.6,则 FF=0.0。亲爱的读者,在您的例子中,FF 结果可能带来完全不同的标准。
收集遗传算法性能结果:对于移动平均线的相交,这些显然是移动平均周期,对于神经网络,有突触权重,它们共有的结果(以及我的其他 EA 的结果)是直到下一次再优化为止要交易的金融工具,以及我们已经熟悉的 optF,即要用于交易的保证金的一部分。由您自主决定向您的 FF 添加优化参数,例如还可以选择时间框架或其他参数。
初始化的最后一步是找出最大帐户余额值。为什么它很重要?因为这是再优化决策的起点。
重要须知!再优化的决策过程:一旦相对余额亏损达到作为外部变量设置的某个临界值(在我们的例子中为 0.2),则我们需要再优化。为了不让 EA 在到达临界亏损时在每一根柱上实施再优化,最大余额值被当前值所代替。
我们要么等待 Forex 的董事打电话来,要求不要破坏世界,或者(更有可能)止损离场、追加保证金或等待救护车。
请在下面找出针对使用移动平均线策略的 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 交易的整个理念基于适应度函数中某个时间段(比如 10000 根柱的历史)内的交易过程(与在 MetaQuotes 的标准测试程序中一样)的模拟,该函数从遗传算法(GA 函数)接收优化变量的输入)。如果算法基于移动平均线的相交,则优化变量包括:
以下示例说明了用于测试的 EA 交易的一种情形!
可以使用来自 MarketWatch (市场报价)窗口的工具列表显著简化真实交易代码。
为此,在带有注释 "//--- GA is selecting a pair"(GA 正在选择一个货币对) 和 "//--- saving the best pair"(保存最佳货币对) 的 FF 和 GetTrainResults() 函数中,仅仅写为:
//--- 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。
我们进一步检查历史中的可用柱数,我们或从第 10000 根柱开始,或从模拟 "Open prices only"(仅开盘价)模式中接收报价过程的第一根柱开始,以及做出交易决定:
- 模拟平仓和余额变更:当前余额增加当前余额值,乘以要交易的保证金部分,再乘以开盘价和收盘价之差,再乘以价格利润点价格(近似);
- 检查当前余额是否达到交易模拟历史中的最大值;如果未达到,计算资金的最大余额亏损;
- 将先前计算出来的资金亏损转换为相对余额亏损;
遍历整个可用历史并模拟虚拟交易之后,计算最终的 FF 值:如果计算出来的相对余额亏损小于为测试设置的亏损,则 FF=余额,否则 FF=0。遗传算法旨在让适应度函数最大化!
最后,给出工具、保证金部分和移动平均线的周期等各个值之后,遗传算法将找出以最小相对亏损(最小值由用户设定)实现最大余额的值。
以下是简要总结:创建一个自训练 EA 交易很容易,困难之处在于找出要输入什么(重要的是想法,实施只是一个技术问题)。
悲观主义者会问 - “它有用吗?”,我的回答 - 有用;对于乐观主义者 - 这不是万能圣杯。
所提议的方法与 Quantum 的方法有什么根本区别?可以通过比较使用移动平均线的 EA 交易来最好地说明这一点:
以下是在测试程序中用 2010 年 1 月 1 起的日线图数据,在没有经过任何优化的情况下运行神经网络所得到的结果:
策略测试程序报告 |
||||||||||||
MetaQuotes-Demo (Build 523) |
||||||||||||
EA 交易: | ANNExample | |||||||||||
交易品种: | EURUSD | |||||||||||
周期: | 每日 (2010.01.01 - 2011.09.30) | |||||||||||
输入参数: | trainDD=0.9 | |||||||||||
maxDD=0.1 | ||||||||||||
经纪人: | Alpari NZ Limited | |||||||||||
货币: | USD | |||||||||||
初始存入: | 10 000.00 | |||||||||||
杠杆率: | 1:100 | |||||||||||
结果 |
||||||||||||
历史质量: | 100% | |||||||||||
柱数: | 454 | 价格变动: | 2554879 | |||||||||
总净利润: | -9 094.49 | 毛利: | 29 401.09 | 毛损: | -38 495.58 | |||||||
获利系数: | 0.76 | 预计获利: | -20.53 | 保证金水平: | 732.30% | |||||||
回收系数: | -0.76 | 夏普比率: | -0.06 | OnTester 结果: | 0 | |||||||
余额亏损: | ||||||||||||
绝对余额亏损: | 9 102.56 | 最大余额亏损: | 11 464.70 (92.74%) | 相对余额亏损: | 92.74% (11 464.70) | |||||||
市值亏损: | ||||||||||||
绝对市值亏损: | 9 176.99 | 最大市值亏损: | 11 904.00 (93.53%) | 相对市值亏损: | 93.53% (11 904.00) | |||||||
总交易次数: | 443 | 短线交易次数(获利%): | 7 (14.29%) | 长线交易次数(获利%): | 436 (53.44%) | |||||||
总成交次数: | 886 | 盈利交易次数(总交易次数的%): | 234 (52.82%) | 亏损交易次数(总交易次数的%): | 209 (47.18%) | |||||||
最大获利交易: | 1 095.57 | 最大亏损交易: | -1 438.85 | |||||||||
平均获利交易: | 125.65 | 平均亏损交易: | -184.19 | |||||||||
最大连续盈利次数(盈利金额): | 8 (397.45) | 最大连续亏损次数(亏损金额): | 8 (-1 431.44) | |||||||||
最大连续收益金额(盈利次数): | 1 095.57 (1) | 最大连续损失金额(亏损次数): | -3 433.21 (6) | |||||||||
平均连续盈利次数: | 2 | 平均连续亏损次数: | 2 |
以下是供选择的三种再优化情形:
第一种...
时间 | 成交 | 交易品种 | 类型 | 方向 | 交易量 | 价格 | 订单 | 库存费 | 盈利 | 余额 |
2010.01.01 00:00 | 1 | 余额 | 0.00 | 10 000.00 | 10 000.00 | |||||
2010.01.04 00:00 | 2 | AUDUSD | 买 | 入 | 0.90 | 0.89977 | 2 | 0.00 | 0.00 | 10 000.00 |
2010.01.05 00:00 | 3 | AUDUSD | 卖 | 出 | 0.90 | 0.91188 | 3 | 5.67 | 1 089.90 | 11 095.57 |
2010.01.05 00:00 | 4 | AUDUSD | 买 | 入 | 0.99 | 0.91220 | 4 | 0.00 | 0.00 | 11 095.57 |
2010.01.06 00:00 | 5 | AUDUSD | 卖 | 出 | 0.99 | 0.91157 | 5 | 6.24 | -62.37 | 11 039.44 |
2010.01.06 00:00 | 6 | AUDUSD | 买 | 入 | 0.99 | 0.91190 | 6 | 0.00 | 0.00 | 11 039.44 |
2010.01.07 00:00 | 7 | AUDUSD | 卖 | 出 | 0.99 | 0.91924 | 7 | 18.71 | 726.66 | 11 784.81 |
第二种...
时间 | 成交 | 交易品种 | 类型 | 方向 | 交易量 | 价格 | 订单 | 手续费 | 库存费 | 盈利 | 余额 |
2010.05.19 00:00 | 189 | AUDUSD | 卖 | 出 | 0.36 | 0.86110 | 189 | 0.00 | 2.27 | -595.44 | 4 221.30 |
2010.05.19 00:00 | 190 | EURAUD | 卖 | 入 | 0.30 | 1.41280 | 190 | 0.00 | 0.00 | 0.00 | 4 221.30 |
2010.05.20 00:00 | 191 | EURAUD | 买 | 出 | 0.30 | 1.46207 | 191 | 0.00 | 7.43 | -1 273.26 | 2 955.47 |
2010.05.20 00:00 | 192 | AUDUSD | 买 | 入 | 0.21 | 0.84983 | 192 | 0.00 | 0.00 | 0.00 | 2 955.47 |
第三种
时间 | 成交 | 交易品种 | 类型 | 方向 | 交易量 | 价格 | 订单 | 库存费 | 盈利 | 余额 |
2010.06.16 00:00 | 230 | GBPCHF | 买 | 入 | 0.06 | 1.67872 | 230 | 0.00 | 0.00 | 2 128.80 |
2010.06.17 00:00 | 231 | GBPCHF | 卖 | 出 | 0.06 | 1.66547 | 231 | 0.13 | -70.25 | 2 058.68 |
2010.06.17 00:00 | 232 | GBPCHF | 买 | 入 | 0.06 | 1.66635 | 232 | 0.00 | 0.00 | 2 058.68 |
2010.06.18 00:00 | 233 | GBPCHF | 卖 | 出 | 0.06 | 1.64705 | 233 | 0.04 | -104.14 | 1 954.58 |
2010.06.18 00:00 | 234 | AUDUSD | 买 | 入 | 0.09 | 0.86741 | 234 | 0.00 | 0.00 | 1 954.58 |
2010.06.21 00:00 | 235 | AUDUSD | 卖 | 出 | 0.09 | 0.87184 | 235 | 0.57 | 39.87 | 1 995.02 |
2010.06.21 00:00 | 236 | AUDUSD | 买 | 入 | 0.09 | 0.88105 | 236 | 0.00 | 0.00 | 1 995.02 |
2010.06.22 00:00 | 237 | AUDUSD | 卖 | 出 | 0.09 | 0.87606 | 237 | 0.57 | -44.91 | 1 950.68 |
2010.06.22 00:00 | 238 | AUDUSD | 买 | 入 | 0.09 | 0.87637 | 238 | 0.00 | 0.00 | 1 950.68 |
2010.06.23 00:00 | 239 | AUDUSD | 卖 | 出 | 0.09 | 0.87140 | 239 | 0.57 | -44.73 | 1 906.52 |
2010.06.23 00:00 | 240 | AUDUSD | 买 | 入 | 0.08 | 0.87197 | 240 | 0.00 | 0.00 | 1 906.52 |
2010.06.24 00:00 | 241 | AUDUSD | 卖 | 出 | 0.08 | 0.87385 | 241 | 1.51 | 15.04 | 1 923.07 |
2010.06.24 00:00 | 242 | AUDUSD | 买 | 入 | 0.08 | 0.87413 | 242 | 0.00 | 0.00 | 1 923.07 |
2010.06.25 00:00 | 243 | AUDUSD | 卖 | 出 | 0.08 | 0.86632 | 243 | 0.50 | -62.48 | 1 861.09 |
2010.06.25 00:00 | 244 | AUDUSD | 买 | 入 | 0.08 | 0.86663 | 244 | 0.00 | 0.00 | 1 861.09 |
2010.06.28 00:00 | 245 | AUDUSD | 卖 | 出 | 0.08 | 0.87375 | 245 | 0.50 | 56.96 | 1 918.55 |
2010.06.28 00:00 | 246 | AUDUSD | 买 | 入 | 0.08 | 0.87415 | 246 | 0.00 | 0.00 | 1 918.55 |
2010.06.29 00:00 | 247 | AUDUSD | 卖 | 出 | 0.08 | 0.87140 | 247 | 0.50 | -22.00 | 1 897.05 |
2010.06.29 00:00 | 248 | AUDUSD | 买 | 入 | 0.08 | 0.87173 | 248 | 0.00 | 0.00 | 1 897.05 |
2010.07.01 00:00 | 249 | AUDUSD | 卖 | 出 | 0.08 | 0.84053 | 249 | 2.01 | -249.60 | 1 649.46 |
2010.07.01 00:00 | 250 | EURGBP | 卖 | 入 | 0.07 | 0.81841 | 250 | 0.00 | 0.00 | 1 649.46 |
2010.07.02 00:00 | 251 | EURGBP | 买 | 出 | 0.07 | 0.82535 | 251 | -0.04 | -73.69 | 1 575.73 |
2010.07.02 00:00 | 252 | EURGBP | 卖 | 入 | 0.07 | 0.82498 | 252 | 0.00 | 0.00 | 1 575.73 |
2010.07.05 00:00 | 253 | EURGBP | 买 | 出 | 0.07 | 0.82676 | 253 | -0.04 | -18.93 | 1 556.76 |
2010.07.05 00:00 | 254 | EURGBP | 卖 | 入 | 0.06 | 0.82604 | 254 | 0.00 | 0.00 | 1 556.76 |
2010.07.06 00:00 | 255 | EURGBP | 买 | 出 | 0.06 | 0.82862 | 255 | -0.04 | -23.43 | 1 533.29 |
附言:作为一项家庭作业:不仅选择某个系统的参数,还选择在某个时刻最符合市场的系统(提示 - 从系统库中选择)。
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程