|
首先,我们来谈谈测试程序。在测试开始之前,测试的子系统加载智能交易,设定用户指定的先前参量并且调用init()函数。随后通过生成次序测试开始,并且每次都会调用 start()函数。当测试的次序耗尽,会调用 deinit()函数。这样,整个交易历史在测试期间产生测试数据。在此时这个智能交易的效率可以进行分析。
CalculateSummary函数提供以下测试结果计算,即,在策略测试的标准报告中给出数据。
- void CalculateSummary(double initial_deposit)
- {
- int sequence=0, profitseqs=0, lossseqs=0;
- double sequential=0.0, prevprofit=EMPTY_VALUE, drawdownpercent, drawdown;
- double maxpeak=initial_deposit, minpeak=initial_deposit, balance=initial_deposit;
- int trades_total=HistoryTotal();
- //---- 初始化总结
- InitializeSummaries(initial_deposit);
- //----
- for(int i=0; i<trades_total; i++)
- {
- if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
- int type=OrderType();
- //---- 不考虑初始差额
- if(i==0 && type==OP_BALANCE) continue;
- //---- 计算赢利
- double profit=OrderProfit()+OrderCommission()+OrderSwap();
- balance+=profit;
- //---- 检测借款
- if(maxpeak<balance)
- {
- drawdown=maxpeak-minpeak;
- if(maxpeak!=0.0)
- {
- drawdownpercent=drawdown/maxpeak*100.0;
- if(RelDrawdownPercent<drawdownpercent)
- {
- RelDrawdownPercent=drawdownpercent;
- RelDrawdown=drawdown;
- }
- }
- if(MaxDrawdown<drawdown)
- {
- MaxDrawdown=drawdown;
- if(maxpeak!=0.0) MaxDrawdownPercent=MaxDrawdown/maxpeak*100.0;
- else MaxDrawdownPercent=100.0;
- }
- maxpeak=balance;
- minpeak=balance;
- }
- if(minpeak>balance) minpeak=balance;
- if(MaxLoss>balance) MaxLoss=balance;
- //---- 仅限市场定单
- if(type!=OP_BUY && type!=OP_SELL) continue;
- SummaryProfit+=profit;
- SummaryTrades++;
- if(type==OP_BUY) LongTrades++;
- else ShortTrades++;
- //---- 亏损交易
- if(profit<0)
- {
- LossTrades++;
- GrossLoss+=profit;
- if(MinProfit>profit) MinProfit=profit;
- //---- fortune changed
- if(prevprofit!=EMPTY_VALUE && prevprofit>=0)
- {
- if(ConProfitTrades1<sequence ||
- (ConProfitTrades1==sequence && ConProfit2<sequential))
- {
- ConProfitTrades1=sequence;
- ConProfit1=sequential;
- }
- if(ConProfit2<sequential ||
- (ConProfit2==sequential && ConProfitTrades1<sequence))
- {
- ConProfit2=sequential;
- ConProfitTrades2=sequence;
- }
- profitseqs++;
- AvgConWinners+=sequence;
- sequence=0;
- sequential=0.0;
- }
- }
- //---- 赢利交易(profit>=0)
- else
- {
- ProfitTrades++;
- if(type==OP_BUY) WinLongTrades++;
- if(type==OP_SELL) WinShortTrades++;
- GrossProfit+=profit;
- if(MaxProfit<profit) MaxProfit=profit;
- //---- fortune changed
- if(prevprofit!=EMPTY_VALUE && prevprofit<0)
- {
- if(ConLossTrades1<sequence ||
- (ConLossTrades1==sequence && ConLoss2>sequential))
- {
- ConLossTrades1=sequence;
- ConLoss1=sequential;
- }
- if(ConLoss2>sequential ||
- (ConLoss2==sequential && ConLossTrades1<sequence))
- {
- ConLoss2=sequential;
- ConLossTrades2=sequence;
- }
- lossseqs++;
- AvgConLosers+=sequence;
- sequence=0;
- sequential=0.0;
- }
- }
- sequence++;
- sequential+=profit;
- //----
- prevprofit=profit;
- }
- //---- 最终借款检验
- drawdown=maxpeak-minpeak;
- if(maxpeak!=0.0)
- {
- drawdownpercent=drawdown/maxpeak*100.0;
- if(RelDrawdownPercent<drawdownpercent)
- {
- RelDrawdownPercent=drawdownpercent;
- RelDrawdown=drawdown;
- }
- }
- if(MaxDrawdown<drawdown)
- {
- MaxDrawdown=drawdown;
- if(maxpeak!=0) MaxDrawdownPercent=MaxDrawdown/maxpeak*100.0;
- else MaxDrawdownPercent=100.0;
- }
- //---- 考虑最后交易
- if(prevprofit!=EMPTY_VALUE)
- {
- profit=prevprofit;
- if(profit<0)
- {
- if(ConLossTrades1<sequence ||
- (ConLossTrades1==sequence && ConLoss2>sequential))
- {
- ConLossTrades1=sequence;
- ConLoss1=sequential;
- }
- if(ConLoss2>sequential ||
- (ConLoss2==sequential && ConLossTrades1<sequence))
- {
- ConLoss2=sequential;
- ConLossTrades2=sequence;
- }
- lossseqs++;
- AvgConLosers+=sequence;
- }
- else
- {
- if(ConProfitTrades1<sequence ||
- (ConProfitTrades1==sequence && ConProfit2<sequential))
- {
- ConProfitTrades1=sequence;
- ConProfit1=sequential;
- }
- if(ConProfit2<sequential ||
- (ConProfit2==sequential && ConProfitTrades1<sequence))
- {
- ConProfit2=sequential;
- ConProfitTrades2=sequence;
- }
- profitseqs++;
- AvgConWinners+=sequence;
- }
- }
- //---- 收集完毕
- double dnum, profitkoef=0.0, losskoef=0.0, avgprofit=0.0, avgloss=0.0;
- //---- 连续盈利和亏损的平均数
- dnum=AvgConWinners;
- if(profitseqs>0) AvgConWinners=dnum/profitseqs+0.5;
- dnum=AvgConLosers;
- if(lossseqs>0) AvgConLosers=dnum/lossseqs+0.5;
- //---- 绝对值
- if(GrossLoss<0.0) GrossLoss*=-1.0;
- if(MinProfit<0.0) MinProfit*=-1.0;
- if(ConLoss1<0.0) ConLoss1*=-1.0;
- if(ConLoss2<0.0) ConLoss2*=-1.0;
- //---- 赢利原因
- if(GrossLoss>0.0) ProfitFactor=GrossProfit/GrossLoss;
- //----期待盈利
- if(ProfitTrades>0) avgprofit=GrossProfit/ProfitTrades;
- if(LossTrades>0) avgloss =GrossLoss/LossTrades;
- if(SummaryTrades>0)
- {
- profitkoef=1.0*ProfitTrades/SummaryTrades;
- losskoef=1.0*LossTrades/SummaryTrades;
- ExpectedPayoff=profitkoef*avgprofit-losskoef*avgloss;
- }
- //---- 绝对借款
- AbsoluteDrawdown=initial_deposit-MaxLoss;
- }
复制代码
计算正确,机会得知初始化存款额的值 。这样,在init() 函数中AccountBalance()函数必须被调用,在测试开始时将给出差额。
- void init()
- {
- ExtInitialDeposit=AccountBalance();
- }
复制代码
在上面的CalculateSummary 函数中, 与标准的报告一样,盈利在当前的存款额中计算。其他交易结果,像"最大盈利交易" 或 "最大连续亏损"在赢利基础上计算,同样要测量金钱数。随后重新以点数计算赢利。
- ...
- //---- 仅限市场定单
- if(type!=OP_BUY && type!=OP_SELL) continue;
- //---- 以点数计算赢利
- profit=(OrderClosePrice()-OrderOpenPrice())/MarketInfo(OrderSymbol(),MODE_POINT);
- SummaryProfit+=profit;
- ...
复制代码
使用函数将得到结果写入报告文件中。
- void WriteReport(string report_name)
- {
- int handle=FileOpen(report_name,FILE_CSV|FILE_WRITE,'\t');
- if(handle<1) return;
- //----
- FileWrite(handle,"Initial deposit ",InitialDeposit);
- FileWrite(handle,"Total net profit ",SummaryProfit);
- FileWrite(handle,"Gross profit ",GrossProfit);
- FileWrite(handle,"Gross loss ",GrossLoss);
- if(GrossLoss>0.0)
- FileWrite(handle,"Profit factor ",ProfitFactor);
- FileWrite(handle,"Expected payoff ",ExpectedPayoff);
- FileWrite(handle,"Absolute drawdown ",AbsoluteDrawdown);
- FileWrite(handle,"Maximal drawdown ",
- MaxDrawdown,
- StringConcatenate("(",MaxDrawdownPercent,"%)"));
- FileWrite(handle,"Relative drawdown ",
- StringConcatenate(RelDrawdownPercent,"%"),
- StringConcatenate("(",RelDrawdown,")"));
- FileWrite(handle,"Trades total ",SummaryTrades);
- if(ShortTrades>0)
- FileWrite(handle,"Short positions(won %) ",
- ShortTrades,
- StringConcatenate("(",100.0*WinShortTrades/ShortTrades,"%)"));
- if(LongTrades>0)
- FileWrite(handle,"Long positions(won %) ",
- LongTrades,
- StringConcatenate("(",100.0*WinLongTrades/LongTrades,"%)"));
- if(ProfitTrades>0)
- FileWrite(handle,"Profit trades (% of total)",
- ProfitTrades,
- StringConcatenate("(",100.0*ProfitTrades/SummaryTrades,"%)"));
- if(LossTrades>0)
- FileWrite(handle,"Loss trades (% of total) ",
- LossTrades,
- StringConcatenate("(",100.0*LossTrades/SummaryTrades,"%)"));
- FileWrite(handle,"Largest profit trade ",MaxProfit);
- FileWrite(handle,"Largest loss trade ",-MinProfit);
- if(ProfitTrades>0)
- FileWrite(handle,"Average profit trade ",GrossProfit/ProfitTrades);
- if(LossTrades>0)
- FileWrite(handle,"Average loss trade ",-GrossLoss/LossTrades);
- FileWrite(handle,"Average consecutive wins ",AvgConWinners);
- FileWrite(handle,"Average consecutive losses",AvgConLosers);
- FileWrite(handle,"Maximum consecutive wins (profit in money)",
- ConProfitTrades1,
- StringConcatenate("(",ConProfit1,")"));
- FileWrite(handle,"Maximum consecutive losses (loss in money)",
- ConLossTrades1,
- StringConcatenate("(",-ConLoss1,")"));
- FileWrite(handle,"Maximal consecutive profit (count of wins)",
- ConProfit2,
- StringConcatenate("(",ConProfitTrades2,")"));
- FileWrite(handle,"Maximal consecutive loss (count of losses)",
- -ConLoss2,
- StringConcatenate("(",ConLossTrades2,")"));
- //----
- FileClose(handle);
- }
复制代码
以下给出范例,如何使用这些函数生成报告。
- void deinit()
- {
- if(!IsOptimization())
- {
- if(!IsTesting()) ExtInitialDeposit=CalculateInitialDeposit();
- CalculateSummary(ExtInitialDeposit);
- WriteReport("MACD_Sample_Report.txt");
- }
- }
复制代码
在上边的范例中,您能够看到报告结果不仅是在测试结束后生成, 智能交易的运作中。您也许会问如果在终端内账户历史没有全部下载(例如,在账户栏中仅下载一个月的账户历史),怎样获取初始存款额的大小呢。 CalculateInitialDeposit 函数将会帮助解决这个问题。
- double CalculateInitialDeposit()
- {
- double initial_deposit=AccountBalance();
- //----
- for(int i=HistoryTotal()-1; i>=0; i--)
- {
- if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
- int type=OrderType();
- //---- 不考虑初始化差额
- if(i==0 && type==OP_BALANCE) break;
- if(type==OP_BUY || type==OP_SELL)
- {
- //---- 计算赢利
- double profit=OrderProfit()+OrderCommission()+OrderSwap();
- //---- 并减少差额
- initial_deposit-=profit;
- }
- if(type==OP_BALANCE || type==OP_CREDIT)
- initial_deposit-=OrderProfit();
- }
- //----
- return(initial_deposit);
- }
复制代码 在MetaTrader 4 客户端内测试报告会以这种形式生成。
可以比较使用于独立程序的计算数据。
- Initial deposit 10000
- Total net profit -13.16
- Gross profit 20363.32
- Gross loss 20376.48
- Profit factor 0.99935416
- Expected payoff -0.01602923
- Absolute drawdown 404.28
- Maximal drawdown 1306.36 (11.5677%)
- Relative drawdown 11.5966% (1289.78)
- Trades total 821
- Short positions(won %) 419 (24.821%)
- Long positions(won %) 402 (31.592%)
- Profit trades (% of total) 231 (28.1364%)
- Loss trades (% of total) 590 (71.8636%)
- Largest profit trade 678.08
- Largest loss trade -250
- Average profit trade 88.15290043
- Average loss trade -34.53640678
- Average consecutive wins 1
- Average consecutive losses 4
- Maximum consecutive wins (profit in money) 4 (355.58)
- Maximum consecutive losses (loss in money) 15 (-314.74)
- Maximal consecutive profit (count of wins) 679.4 (2)
- Maximal consecutive loss (count of losses) -617.16 (8)
复制代码
该文章的附加文件SummaryReport.mq4 建议保存在目录experts\include 中并且使用 #include 开启。
- #include <SummaryReport.mq4>
-
- double ExtInitialDeposit;
复制代码
|
|