# Dr. Tradelove 或我如何不再担忧并创建一个自训练 EA 交易

7 三月 2014, 07:21
0
1 650

### 正在进行的工作

//+------------------------------------------------------------------+
//| 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.symbol=PositionGetSymbol(0);
request.type_filling=ORDER_FILLING_FOK;
{
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(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID);
}
OrderSend(request,result);
Sleep(10000);
}
}
//+------------------------------------------------------------------+
//|  OpenPosition                                                    |
//+------------------------------------------------------------------+
void OpenPosition()
{
double vol;
request.symbol=s;
request.type_filling=ORDER_FILLING_FOK;
{
request.sl=NULL;
request.tp=NULL;
request.deviation=100;
}
vol=MathFloor(AccountInfoDouble(ACCOUNT_FREEMARGIN)*optF*AccountInfoInteger(ACCOUNT_LEVERAGE)
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(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID);
}
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(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID);
}
OrderSend(request,result);
Sleep(10000);
PositionSelect(s);
}
}
//+------------------------------------------------------------------+

• s - 交易工具，GA 优化的变量之一，
• optF - 用于交易的保证金部分（GA 优化的另一个变量），
• GetPossibleLots() 函数 - 返回用于交易的保证金部分：
//+------------------------------------------------------------------+
//|  GetPossibleLots                                                 |
//+------------------------------------------------------------------+
double GetPossibleLots()
{
request.volume=1.0;
if(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID);
OrderCheck(request,check);
return(NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)/check.margin,2));
}

//+------------------------------------------------------------------+
//|  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);
}

• 一个使用移动平均线的相交进行交易（黄金交叉 - 我们买入金融工具，死亡交叉 - 我们卖出）；
• 另一个是简单的神经网络，接收最后五个交易会话中 [0..1] 范围内的价格变动。

1. 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 在到达临界亏损时在每一根柱上实施再优化，最大余额值被当前值所代替。

亲爱的读者，对于再优化的实施，您可能有完全不同的标准。

2. 正在进行的交易。

3. 在每一次平仓时，我们检查余额亏损是否达到临界值。如果达到临界值，我们运行 GA 并收集其性能结果（这就是再优化）！

4. 我们要么等待 Forex 的董事打电话来，要求不要破坏世界，或者（更有可能）止损离场、追加保证金或等待救护车。

//+------------------------------------------------------------------+
//| 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)
{
{
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])
{
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
//--- 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 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);
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
{
{
CopyOpen(s,tf,from,count,o);
if(t>0) t=t+t*optF*leverage*(o[1]-OpenPrice)*dig/contractSize; else t=0;
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];
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;
OpenPrice=o[1];
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 11: {s="USDCHF"; break;};
case 12: {s="USDJPY"; break;};
default: {s="EURUSD"; break;};
}
//--- saving the best optimal F
optF=Chromosome[GeneCount];
}
//+------------------------------------------------------------------+

• 工具（在 Forex 中为货币对）；是的，它是典型的多货币 EA 交易并且遗传算法选择一个工具（因为代码来自为参加锦标赛而编写的 EA 交易，它有与锦标赛的货币对相对应的货币对；一般而言，可以是经纪人报价的任何工具）。
注：很不幸，EA 交易不能在测试模式中从 MarketWatch （市场报价）窗口中获得货币对列表（感谢 MetaQuotes 用户，我们在这里澄清这一点 - 没门！）。因此，如果您想在测试程序中单独为外汇和股票运行 EA 交易，请在 FF 和 GetTrainResults() 函数中指定您自己的工具。
• 用于交易的保证金部分；
• 两条移动平均线的周期。

//--- GA is selecting a pair
z=(int)MathRound(Colony[GeneCount-1][chromos]*(SymbolsTotal(true)-1));
s=SymbolName(z,true);

• 将移动平均线的值复制到缓存；
• 检查是否为死亡交叉。
• 如果有死亡交叉，并且没有未平仓位 (if(trig==false)) - 建立一个虚拟卖出仓位（仅仅记住建仓价和方向）；
1. 模拟平仓和余额变更：当前余额增加当前余额值，乘以要交易的保证金部分，再乘以开盘价和收盘价之差，再乘以价格利润点价格（近似）；
2. 检查当前余额是否达到交易模拟历史中的最大值；如果未达到，计算资金的最大余额亏损；
3. 将先前计算出来的资金亏损转换为相对余额亏损；
• 建立一个虚拟卖出仓位（仅仅记住建仓价和方向）；
• 对黄金交叉进行相同的检查和计算。

### 总结

1. 自适应训练系统中移动平均线的周期应在编译和严格编码之前决定，并且只能在这种数量有限的情形之中做出选择；在遗传优化 EA 交易中，我们在编译之前不做任何决定，此决定由 GA 做出，并且情形的数量仅受判断力的限制。
2. 自适应交易系统中的虚拟交易是柱到柱；在遗传优化 EA 交易中很少如此 - 并且仅在再优化的条件出现时。受策略、参数、工具数量不断增长影响的计算机性能或许是自适应交易系统的一个限制因素。

### 附录

 策略测试程序报告 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

anntrainlib.mqh (9.76 KB)
matrainlib.mqh (8.94 KB)
ugalib.mqh (33.26 KB)
annexample.mq5 (4.32 KB)
maexample.mq5 (4.22 KB)
musthavelib.mqh (8.14 KB)

Box-Cox 变换

MQL5 编程基础：时间