
使用 SMA 和 EMA 自动优化止盈和指标参数的示例
概述
在不断发展的算法交易世界中,创新是保持领先地位的关键。今天,我们很高兴推出一款复杂的 EA 交易系统,它将机器学习与传统的技术分析相结合,以驾驭外汇市场。该 EA 利用 ONNX 模型和精心优化的技术指标在货币市场做出交易决策。
EA 的方法是多方面的,利用机器学习模型的价格预测、趋势跟踪技术和自适应参数优化。它的设计主要针对 #AAPL 股票,尽管它具有适应其他工具的灵活性。该 EA 具有动态手数调整、追踪止损和自动调整市场条件等功能,融合了尖端技术与久经考验的交易原则。
所用指标的说明:
- 简单移动平均线(SMA):EA 使用了具有自适应优化周期的简单移动平均线。SMA 有助于确定整体趋势方向,并与价格和其他指标结合使用,以生成交易信号。
- 指数移动平均线(EMA):还采用了指数移动平均线,其周期数经过动态优化。EMA 对近期价格变化的反应比 SMA 更快,为趋势方向提供了不同的视角。
- 平均真实范围(ATR):虽然代码中没有明确计算,但 EA 使用了基于 ATR 的计算来设置止损和止盈水平。这允许根据波动性调整头寸大小和风险管理。
- 机器学习模型:EA 采用 ONNX(开放神经网络交换)模型进行价格预测。该模型采用一系列最近的价格数据,并试图预测下一个价格走势,为交易策略添加预测元素。
这些指标以复杂的方式组合在一起,其参数根据最近的市场状况动态优化。EA 还包括追踪止损和道德期望计算等功能,以有效管理未平仓头寸。
这些指标的结合,以及机器学习组件,使EA能够适应不断变化的市场条件,并可能识别各种市场状态的交易机会。
代码解析
1.初始设置和包含文件:
代码以版权信息开头,并包含了 Trade.mqh 等必要的库。
#include <Trade\Trade.mqh>
2.全局变量和参数:
- 定义了 ONNX 模型参数,包括样本大小和句柄。
- 声明了指标 (SMA、EMA、ATR) 和交易操作的输入参数。
- 定义了价格变动和幻数的枚举和常量。
#resource "/Files/model.EURUSD.D1.1_1_2024.onnx" as uchar ExtModel[];
input group "----- Indicators Parameters -----" int SMA_Period = 20; int EMA_Period = 50; input double StopLossATR = 1.5; input double TakeProfitATR = 3.0; input int OptimizationDays = 1; // Hours between optimizations input int LookbackPeriod = 7; // Hours loockback periods input int MinSMAPeriod = 5; // Period min para SMA input int MaxSMAPeriod = 50; // Periodo max para SMA input int MinEMAPeriod = 5; // Periodo min para EMA input int MaxEMAPeriod = 50; // Periodo max para EMA
#define MAGIC_SE 12321
datetime lastOptimizationTime = 0; double optimizedTakeProfit = 0.0;//InpTakeProfit; double optimizedStopLoss = 0.0;//InpStopLoss;
double InpTakeProfit1 ; double InpStopLoss1;
3.初始化函数(OnInit):
- 从缓冲区设置 ONNX 模型。
- 初始化技术指标(SMA、EMA)。
- 调用函数来优化指标和交易参数。
int OnInit() { //--- create a model from static buffer ExtHandle = OnnxCreateFromBuffer(ExtModel, ONNX_DEFAULT); if(ExtHandle == INVALID_HANDLE) { Print("OnnxCreateFromBuffer error ", GetLastError()); return(INIT_FAILED); } //--- set input and output shapes const long input_shape[] = {1, SAMPLE_SIZE, 1}; if(!OnnxSetInputShape(ExtHandle, ONNX_DEFAULT, input_shape)) { Print("OnnxSetInputShape error ", GetLastError()); return(INIT_FAILED); } const long output_shape[] = {1, 1}; if(!OnnxSetOutputShape(ExtHandle, 0, output_shape)) { Print("OnnxSetOutputShape error ", GetLastError()); return(INIT_FAILED); } SMAHandle = iMA(_Symbol, _Period, SMA_Period, 0, MODE_SMA, PRICE_CLOSE); // Ensure correct period if(SMAHandle == INVALID_HANDLE) { Print("Error initializing SMA indicator: ", GetLastError()); return INIT_FAILED; } EMAHandle = iMA(_Symbol, _Period, EMA_Period, 0, MODE_EMA, PRICE_CLOSE); // Ensure correct index if(EMAHandle == INVALID_HANDLE) { Print("Error initializing EMA indicator: ", GetLastError()); return INIT_FAILED; }
trade.SetDeviationInPoints(Slippage); trade.SetExpertMagicNumber(MAGIC_SE);
OptimizeIndicators(); OptimizeParameters(); return(INIT_SUCCEEDED); }
4.去初始化函数(OnDeinit):
释放 ONNX 模型和指标的句柄。
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(ExtHandle != INVALID_HANDLE) { OnnxRelease(ExtHandle); ExtHandle = INVALID_HANDLE; } IndicatorRelease(SMAHandle); IndicatorRelease(EMAHandle); }
5.主要交易逻辑(OnTick):
- 检查市场是否关闭。
- 定期优化指标和交易参数。
- 更新追踪止损逻辑。
- 使用 ONNX 模型预测价格走势。
- 根据预测和指标检查开仓/平仓条件。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if(IsMarketClosed()) // Verificar si el mercado está cerrado { return; // Si el mercado está cerrado, no hacer nada } static datetime lastOptimizationTime2 = 0; if(TimeCurrent() - lastOptimizationTime2 >= OptimizationDays * PeriodSeconds(PERIOD_H1)) { OptimizeIndicators(); lastOptimizationTime2 = TimeCurrent(); // Actualizar los indicadores con los nuevos períodos IndicatorRelease(SMAHandle); IndicatorRelease(EMAHandle); SMAHandle = iMA(_Symbol, _Period, SMA_Period, 0, MODE_SMA, PRICE_CLOSE); EMAHandle = iMA(_Symbol, _Period, EMA_Period, 0, MODE_EMA, PRICE_CLOSE); } //--- Optimización cada 2 días if(TimeCurrent() - lastOptimizationTime >= PeriodSeconds(PERIOD_H1) * HoursAnalyze) { OptimizeParameters(); lastOptimizationTime = TimeCurrent(); } //--- if(NewBarTS()==true)//gather statistics and launch trailing stop { double open=iOpen(_Symbol,TFTS,1); CalcLvl(up,(int)MathRound((iHigh(_Symbol,TFTS,1)-open)/_Point)); CalcLvl(dn,(int)MathRound((open-iLow(_Symbol,TFTS,1))/_Point)); buy_sl=CalcSL(dn); buy_tp=CalcTP(up); sell_sl=CalcSL(up); sell_tp=CalcTP(dn); if(TypeTS==Simple)//simple trailing stop SimpleTS(); if(TypeTS==MoralExp)//Moral expectation METS(); if(TypeTS==None)//None TS return; } double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID); if(bid==SLNeutral || bid<=SLBuy || (SLSell>0 && bid>=SLSell)) { for(int i=PositionsTotal()-1; i>=0; i--) { ulong ticket=PositionGetTicket(i); if(PositionSelectByTicket(ticket)==true) trade.PositionClose(ticket); } } //--- //--- check new day if(TimeCurrent() >= ExtNextDay) { GetMinMax(); ExtNextDay = TimeCurrent(); ExtNextDay -= ExtNextDay % PeriodSeconds(PERIOD_D1); ExtNextDay += PeriodSeconds(PERIOD_D1); } //--- check new bar if(TimeCurrent() < ExtNextBar) return; ExtNextBar = TimeCurrent(); ExtNextBar -= ExtNextBar % PeriodSeconds(); ExtNextBar += PeriodSeconds(); //--- check min and max float close = (float)iClose(_Symbol, _Period, 0); if(ExtMin > close) ExtMin = close; if(ExtMax < close) ExtMax = close; double sma[], ema[];//, willr[]; CopyBuffer(SMAHandle, 0, 0, 1, sma); CopyBuffer(EMAHandle, 0, 0, 1, ema); //CopyBuffer(WillRHandle, 0, 0, 1, willr); //--- predict next price PredictPrice(); //--- check trading according to prediction and indicators if(ExtPredictedClass >= 0) { if(PositionSelect(_Symbol)) CheckForClose(sma[0], ema[0]);//, willr[0]); else CheckForOpen(sma[0], ema[0]);//, willr[0]); } }
6.交易函数:
- CheckForOpen:根据预测和指标信号确定是否开立买入或卖出仓位。
- CheckForClose:检查是否应根据预测关闭当前仓位。
//+------------------------------------------------------------------+ //| Check for open position conditions | //+------------------------------------------------------------------+ void CheckForOpen(double sma, double ema)//, double willr) { MqlRates rates[]; ArraySetAsSeries(rates,true); int copied = CopyRates(_Symbol,0,0,1,rates); if(copied <= 0) { Print("Error copying rates: ", GetLastError()); return; } double Close[1]; Close[0]=rates[0].close; double close = Close[0]; ENUM_ORDER_TYPE signal = WRONG_VALUE; Print("ExtPredictedClass ",ExtPredictedClass); //--- check signals if(ExtPredictedClass == 2)//PRICE_DOWN) { Print("ExtPredictedClass Sell ",ExtPredictedClass); Print("close ",close, " sma ",sma, " ema ", ema);//, " willr ", willr); // Venta if((close < sma && close < ema))// || willr > -20) { signal = ORDER_TYPE_SELL; Print("Order Sell detected"); } } else if(ExtPredictedClass == 0)//PRICE_UP) { Print("ExtPredictedClass Buy ",ExtPredictedClass); Print("close ",close, " sma ",sma, " ema ", ema);//, " willr ", willr); // Compra if((close > sma && close > ema))// || willr < -80) { signal = ORDER_TYPE_BUY; Print("Order Buy detected"); } } //--- open position if possible according to signal if(signal != WRONG_VALUE && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) { Print("Proceding open order"); double price, sl=0, tp=0; double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_DEAL; request.symbol = _Symbol; request.deviation = Slippage; request.magic = MAGIC_SE; request.type_filling = ORDER_FILLING_FOK; //request.comment = "AKWr"; double lotaje; if(signal == ORDER_TYPE_SELL) { price = bid; Print("Price: ",price); if(inp_lot_type == LOT_TYPE_FIX) lotaje=inp_lot_fix ; else lotaje=get_lot(price); if(!CheckVolumeValue(lotaje)) return; if(!InpUseStops && ATR) { sl = NormalizeDouble(bid + StopLossATR * ATRValue, _Digits); tp = NormalizeDouble(ask - TakeProfitATR * ATRValue, _Digits); if(!CheckMoneyForTrade(_Symbol, lotaje,ORDER_TYPE_SELL)) { Print("No hay suficiente margen para abrir la posición"); return; } request.type = ORDER_TYPE_SELL; request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID); request.volume = lotaje; request.sl = sl; request.tp = tp; request.comment = "SEW Opened sell order"; } if(!InpUseStops && ATR) { sl = 0; tp = 0; } else { InpTakeProfit1 =optimizedTakeProfit; InpStopLoss1= optimizedStopLoss; sl = NormalizeDouble(bid + InpStopLoss1*_Point, _Digits); tp = NormalizeDouble(ask - InpTakeProfit1*_Point, _Digits); } } else { price = ask; Print("Price: ",price); if(inp_lot_type == LOT_TYPE_FIX) lotaje=inp_lot_fix ; else lotaje=get_lot(price); if(!CheckVolumeValue(lotaje)) return; if(!InpUseStops) { sl = NormalizeDouble(ask - StopLossATR * ATRValue, _Digits); tp = NormalizeDouble(bid + TakeProfitATR * ATRValue, _Digits); if(!CheckMoneyForTrade(_Symbol, lotaje,ORDER_TYPE_BUY)) { Print("No hay suficiente margen para abrir la posición"); return; } request.type = ORDER_TYPE_BUY; request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); request.volume = lotaje; request.sl = sl; request.tp = tp; request.comment = "SEW Opened buy order"; } if(!InpUseStops && ATR) { sl = 0; tp = 0; } else { InpTakeProfit1 =optimizedTakeProfit; InpStopLoss1= optimizedStopLoss; sl = NormalizeDouble(ask - InpStopLoss1*_Point, _Digits); tp = NormalizeDouble(bid + InpTakeProfit1*_Point, _Digits); } } Print("No InpUseStops used"); //ExtTrade.PositionOpen(_Symbol, signal, lotaje, price, sl, tp); if(!CheckMoneyForTrade(_Symbol, lotaje, (ENUM_ORDER_TYPE)signal)) { Print("No hay suficiente margen para abrir la posición"); return; } Print("Volume ", lotaje); request.type = signal; request.price = price;//SymbolInfoDouble(_Symbol, SYMBOL_ASK); request.volume = lotaje; request.sl = sl; request.tp = tp; request.comment = "SEW"; if(!OrderSend(request, result)) { Print("Error opening the order: ", GetLastError()); return; } } } //+------------------------------------------------------------------+ //| Check for close position conditions | //+------------------------------------------------------------------+ void CheckForClose(double sma, double ema)//, double willr) { if(InpUseStops) return; bool bsignal = false; //--- position already selected before long type = PositionGetInteger(POSITION_TYPE); //--- check signals if(type == POSITION_TYPE_BUY && ExtPredictedClass == 2)//PRICE_DOWN) bsignal = true; if(type == POSITION_TYPE_SELL && ExtPredictedClass == 0)//PRICE_UP) bsignal = true; //--- close position if possible if(bsignal && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) { ExtTrade.PositionClose(_Symbol); CheckForOpen(sma, ema);//, willr); } }
7.价格预测(PredictPrice):
使用 ONNX 模型预测未来的价格走势。
//+------------------------------------------------------------------+ //| Predict next price | //+------------------------------------------------------------------+ void PredictPrice(void) { static vectorf output_data(1); static vectorf x_norm(SAMPLE_SIZE); if(ExtMin >= ExtMax) { Print("ExtMin >= ExtMax"); ExtPredictedClass = -1; return; } if(!x_norm.CopyRates(_Symbol, _Period, COPY_RATES_CLOSE, 1, SAMPLE_SIZE)) { Print("CopyRates ", x_norm.Size()); ExtPredictedClass = -1; return; } float last_close = x_norm[SAMPLE_SIZE - 1]; x_norm -= ExtMin; x_norm /= (ExtMax - ExtMin); if(!OnnxRun(ExtHandle, ONNX_NO_CONVERSION, x_norm, output_data)) { Print("OnnxRun"); ExtPredictedClass = -1; return; } float predicted = output_data[0] * (ExtMax - ExtMin) + ExtMin; float delta = last_close - predicted; if(fabs(delta) <= 0.00001) ExtPredictedClass = PRICE_SAME; else if(delta < 0) ExtPredictedClass = PRICE_UP; else ExtPredictedClass = PRICE_DOWN; // Debugging output Print("Predicted price: ", predicted, " Delta: ", delta, " Predicted Class: ", ExtPredictedClass); }
8.追踪止损函数:
有多个函数(AllTS、METS、SimpleTS)实现不同的追踪止损策略。
这篇文章中对此进行了解释: 交易中的追踪止损 - MQL5 文章
9.优化函数:
- OptimizeParameters:尝试不同的止盈和止损值来找到最佳设置。
- OptimizeIndicators:找到 SMA 和 EMA 指标的最佳周期数。
void OptimizeParameters() { double bestTakeProfit = InpTakeProfit1; double bestStopLoss = InpStopLoss1; double bestPerformance = -DBL_MAX; for(int tp = 65; tp <= 500; tp += 5) // rango de TakeProfit { for(int sl = 65; sl <= 500; sl += 5) // rango de StopLoss { double performance = TestStrategy(tp, sl); if(performance > bestPerformance) { bestPerformance = performance; bestTakeProfit = tp; bestStopLoss = sl; //Print("Best Take Profit",bestTakeProfit); //Print("Best Stop Loss",bestStopLoss); } } } optimizedTakeProfit = bestTakeProfit; optimizedStopLoss = bestStopLoss; Print("Optimized TakeProfit: ", optimizedTakeProfit); Print("Optimized StopLoss: ", optimizedStopLoss); }
void OptimizeIndicators() { datetime startTime = TimeCurrent() - LookbackPeriod * PeriodSeconds(PERIOD_H1); datetime endTime = TimeCurrent(); int bestSMAPeriod = SMA_Period; int bestEMAPeriod = EMA_Period; double bestPerformance = -DBL_MAX; for(int smaPeriod = MinSMAPeriod; smaPeriod <= MaxSMAPeriod; smaPeriod++) { for(int emaPeriod = MinEMAPeriod; emaPeriod <= MaxEMAPeriod; emaPeriod++) { double performance = TestIndicatorPerformance(smaPeriod, emaPeriod, startTime, endTime); if(performance > bestPerformance) { bestPerformance = performance; bestSMAPeriod = smaPeriod; bestEMAPeriod = emaPeriod; } } } SMA_Period = bestSMAPeriod; EMA_Period = bestEMAPeriod; Print("Optimized SMA Period: ", SMA_Period); Print("Optimized EMA Period: ", EMA_Period); }
10.工具函数和资金管理::
手数计算、交易量检查、市场收盘检查等函数包括检查交易资金是否足够以及规范手数等函数。
bool IsMarketClosed() { datetime currentTime = TimeCurrent(); MqlDateTime tm; TimeToStruct(currentTime, tm); int dayOfWeek = tm.day_of_week; int hour = tm.hour; // Verifica si es fin de semana if(dayOfWeek <= Sunday || dayOfWeek >= Saturday) { return true; } // Verifica si está fuera del horario habitual de mercado (ejemplo: 21:00 a 21:59 UTC) if(hour >= after || hour < before) // Ajusta estos valores según el horario del mercado { return true; } return false; } //+------------------------------------------------------------------+ //| Check the correctness of the order volume | //+------------------------------------------------------------------+ bool CheckVolumeValue(double volume)//,string &description) { //--- minimal allowed volume for trade operations double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN); if(volume<min_volume) { //description=StringFormat("Volume is less than the minimal allowed SYMBOL_VOLUME_MIN=%.2f",min_volume); return(false); } //--- maximal allowed volume of trade operations double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX); if(volume>max_volume) { //description=StringFormat("Volume is greater than the maximal allowed SYMBOL_VOLUME_MAX=%.2f",max_volume); return(false); } //--- get minimal step of volume changing double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP); int ratio=(int)MathRound(volume/volume_step); if(MathAbs(ratio*volume_step-volume)>0.0000001) { //description=StringFormat("Volume is not a multiple of the minimal step SYMBOL_VOLUME_STEP=%.2f, the closest correct volume is %.2f", //volume_step,ratio*volume_step); return(false); } //description="Correct volume value"; return(true); } //+------------------------------------------------------------------+ bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type) { //--- Getting the opening price MqlTick mqltick; SymbolInfoTick(symb,mqltick); double price=mqltick.ask; if(type==ORDER_TYPE_SELL) price=mqltick.bid; //--- values of the required and free margin double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE); //--- call of the checking function if(!OrderCalcMargin(type,symb,lots,price,margin)) { //--- something went wrong, report and return false Print("Error in ",__FUNCTION__," code=",GetLastError()); return(false); } //--- if there are insufficient funds to perform the operation if(margin>free_margin) { //--- report the error and return false Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError()); return(false); } //--- checking successful return(true); }
double get_lot(double price) { if(inp_lot_type==LOT_TYPE_FIX) return(normalize_lot(inp_lot_fix)); double one_lot_margin; if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,one_lot_margin)) return(inp_lot_fix); return(normalize_lot((AccountInfoDouble(ACCOUNT_BALANCE)*(inp_lot_risk/100))/ one_lot_margin)); } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< double normalize_lot(double lt) { double lot_step = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); lt = MathFloor(lt / lot_step) * lot_step; double lot_minimum = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); lt = MathMax(lt, lot_minimum); return(lt); }
主要特点:
- 使用机器学习(ONNX 模型)进行价格预测。
- 将技术指标(SMA、EMA)与 ML 预测相结合,以做出交易决策。
- 实现了多种追踪止损策略。
- 包括指标参数和交易设置的定期优化。
- 具有内置风险管理(手数调整、资金检查)。
- 考虑到了交易的市场时间。
该 EA 交易非常复杂,将传统的技术分析与外汇交易的机器学习相结合。它还包括各种风险管理和优化功能,以适应不断变化的市场条件。
分析表明,该自动交易策略表现出盈利能力,夏普比率达到 6.21。然而,它的回撤幅度很大,这表明需要谨慎的风险管理。正如净值曲线所示,该策略实现持续收益的能力反映了其在现实世界交易应用的潜力。未来的优化可以集中在减少回撤和提高恢复因子,以提高整体性能。
总结
本文介绍了一种用于外汇市场算法交易的创新型 EA 交易,专为交易 Apple Inc. (#AAPL) 股票而设计。该 EA 是机器学习和传统技术分析的复杂结合,旨在以精确度和适应性应对货币市场的复杂性。
该 EA 的核心是 ONNX(开放神经网络交换)模型,它作为机器学习组件。模型的任务是根据最近的市场数据预测价格走势,为交易策略增加前瞻性元素。EA 将这些预测与已建立的技术指标(即简单移动平均线 (SMA) 和指数移动平均线 (EMA))相结合,以生成交易信号。
EA 的方法是多方面的,包含几个关键特征:
- 动态优化:技术指标和交易参数都会定期优化。这使得 EA 能够适应不断变化的市场条件,并有可能随着时间的推移提高其性能。
- 自适应风险管理:EA 采用动态手数调整并使用平均真实范围 (ATR) 计算来设置止损和止盈水平。这种方法旨在根据当前市场波动调整头寸大小和风险敞口。
- 多种追踪止损策略:该 EA 实现了各种追踪止损方法,可以灵活地管理未平仓头寸,并有可能最大化利润,同时最小化损失。
- 市场条件感知:该系统设计时考虑了市场时间和条件,确保仅在适当的时候执行交易。
本文对 EA 的代码结构进行了详细的分解,阐明了其关键组成部分:
- 初始化:此阶段设置 ONNX 模型和技术指标,为 EA 的运行做好准备。
- 主要交易逻辑:核心功能是根据机器学习模型和技术指标的组合信号来决定何时开仓或平仓。
- 价格预测:应用 ONNX 模型预测未来的价格走势。
- 优化功能:定期调整指标参数和交易设置,以在不同的市场条件下维持有效性。
- 风险管理:包括手数计算、资金管理和市场条件检查等功能。
EA 的性能是通过对 AAPL 股票数据进行回溯测试来评估的,结果显示盈利能力良好,夏普比率为 6.21,表明风险调整后的回报强劲。然而,分析还显示,回撤数字相对较高,表明风险管理方面仍有改进空间。
结论
我们今天拥有的 EA 交易是一个巨大的飞跃。它结合使用智能技术(机器学习)和成熟方法(技术分析),为交易者提供有关如何投资 AAPL 股票和其他交易品种的宝贵会员专属决策。
该 EA 结合 ONNX 模型来通过优化的技术指标来预测价格。这种混合意味着它既能应对即时的价格变化,也能应对长期发展的缓慢波动。
这个 EA 的一个吸引人的地方是它有一个连贯的风险管理系统。例如,它采用动态手数(根据市场情况改变交易规模)、基于 ATR 的止损和止盈水平(如果情况恶化或盈利对你有利,则对你的损失施加限制)以及针对价格变化的多种追踪止损策略。这些工具是专门为保护你的资金而设计的,不会以秘密的方式被榨干。
这个 EA 的另一个优点是它定期更新指标和交易参数。这将使其能够跟上不断变化的市场,这是随着时间的推移保持有效的一个非常重要的组成部分。
然而,从回溯测试分析来看,结果仍然有些令人失望,该分析显示了 EA 过去的表现。尽管从利润和风险管理的角度来看,结果似乎不错,但它确实显示出一些高回撤率 — 价值大幅下降 — 从而表明风险管理可以加强。EA 的未来版本可能包括更好的保障措施,或者在非常动荡的时期进行更谨慎的交易。
尽管它是为交易 AAPL 股票而创建的,但其中的运作原理可以轻松应用于其他金融市场。这种灵活性使该工具在当前交易中以及作为未来算法系统的模型中都值得使用。
这是一个复杂、前景广阔的自动化交易 EA,融合了尖端技术和传统方式,风险管理能力强,能够适应不断变化的市场条件。然而,与任何其他交易工具一样,它确实需要在现实世界中进行定期监控、更新和测试,以确保其功能随着时间的推移而平稳运行。
最后,虽然这个 EA 似乎有很大的潜力,但还需要做更多的工作,还需要做很多优化,但重要的是要记住,交易总是涉及风险,过去的表现并不能保证未来的成功。如果您正在考虑使用这个或任何自动化系统,请确保您了解风险,做好功课,最好在使用真钱之前在模拟环境中进行测试。
我希望你喜欢读这篇文章,就像我喜欢写这篇文章一样,我希望你能把这个 EA 做得更好,取得好成绩。这是一个很好的例子,说明如何使用停止和指标实现自动优化。再说一遍,我希望你喜欢这篇文章。干杯!
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/15476
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.



谢谢!我正在制作,很快就能完成。如果您还有其他要求或需要,请提出来。
下面是这篇文章,希望您喜欢:如何在 MQL5 Expert Advisors 中实现自动优化 - MQL5 文章