
MQL5 细则手册:MetaTrader 5 交易事件的声音通知
简介
在本文中,我们将考虑在“EA 交易”的文件中包含声音文件、从而为交易事件添加声音通知的事宜。将包含文件的事实意味着声音文件将位于“EA 交易”的内部。因此,在向其他用户提供编译后的“EA 交易”版本 (*.ex5) 时,您无需再提供声音文件并说明它们应予以保存的位置。
开发
出于测试目的,我们的 EA 交易取自前文“MQL5 细则手册:保存基于指定标准的“EA 交易”的优化结果”。为使其更加简单,我去除了与当前主题无关的所有因素。
要使用 MQL5 资源为交易事件添加声音通知,我们可以使用 Alert() 和 PlaySound() 函数。如果您选择 Alert() 函数,它将总是播放相同的声音通知并打开一个含相关消息的窗口。您可以在 “MQL5 细则手册:使用不同的打印模式”一文中查看它的运转情况。
警示声可在终端设置中进行设置:Tools(工具)-> Options(选项)或 Ctrl+O。然后在 Events(事件)选项卡中,我们需要勾选 "Enable"(启用)选项以为事件启用声音通知,并在提醒下拉列表中选择相应的声音文件。
图 1. 终端设置中的 "Events"(事件)选项卡
然而,您也可以为任何自定义程序事件设置一个独特的声音通知。为此,我们使用 PlaySound 函数。
在我们将声音文件添加至“EA 交易”之前,让我们创建一个用于测试的“EA 交易”。当在图表上加载“EA 交易”时,让我们实现一个打开声音面板的构想。声音面板将由图形对象构成,例如按钮(OBJ_BUTTON)。每个按钮将具有分配给其的独特声音,声音将在按下按钮时播放。
我在网上找到 25 种 *.wav 格式的不同声音文件(这些在本文的末尾提供下载链接)。必须将它们放在 MetaTrader 5\MQL5\Files\Sounds 文件夹中。要得到使用声音文件的诀窍,现在我们将使用 MQL5 向导创建一个新的“EA 交易”。在最开始,我们基于声音面板上的按钮数目指定数组的大小(总共将有 26 个按钮)。
//--- Array size #define ARRAY_SIZE 26
然后,我们需要指定将为“EA 交易”提供资源的文件夹和文件名称。这可以使用 #resource 指令完成。在该指令后,我们在双引号中指定文件位置:
//--- Sound files #resource "\\Files\\Sounds\\alert.wav" #resource "\\Files\\Sounds\\AHOOGA.wav" #resource "\\Files\\Sounds\\APPLAUSE.wav" #resource "\\Files\\Sounds\\BONK.wav" #resource "\\Files\\Sounds\\CARBRAKE.wav" #resource "\\Files\\Sounds\\CASHREG.wav" #resource "\\Files\\Sounds\\CLAP.wav" #resource "\\Files\\Sounds\\CORKPOP.wav" #resource "\\Files\\Sounds\\DOG.wav" #resource "\\Files\\Sounds\\DRIVEBY.wav" #resource "\\Files\\Sounds\\DRUMROLL.wav" #resource "\\Files\\Sounds\\EXPLODE.wav" #resource "\\Files\\Sounds\\FINALBEL.wav" #resource "\\Files\\Sounds\\FROG.wav" #resource "\\Files\\Sounds\\GLASS.wav" #resource "\\Files\\Sounds\\GUNSHOT.wav" #resource "\\Files\\Sounds\\LASER.wav" #resource "\\Files\\Sounds\\LATNWHIS.wav" #resource "\\Files\\Sounds\\PIG.wav" #resource "\\Files\\Sounds\\RICOCHET.wav" #resource "\\Files\\Sounds\\RINGIN.wav" #resource "\\Files\\Sounds\\SIREN.wav" #resource "\\Files\\Sounds\\TRAIN.wav" #resource "\\Files\\Sounds\\UH_OH.wav" #resource "\\Files\\Sounds\\VERYGOOD.wav" #resource "\\Files\\Sounds\\WHOOSH.wav"
现在,我们需要创建三个字符串数组,用于包含源文件的位置、图形对象的名称以及在图形对象上显示的文本。请注意指定文件位置时使用的双冒号 - 这是按名称调用资源的特别说明。
//--- Sound file location string sound_paths[ARRAY_SIZE]= { "::Files\\Sounds\\alert.wav", "::Files\\Sounds\\AHOOGA.wav", "::Files\\Sounds\\APPLAUSE.wav", "::Files\\Sounds\\BONK.wav", "::Files\\Sounds\\CARBRAKE.wav", "::Files\\Sounds\\CASHREG.wav", "::Files\\Sounds\\CLAP.wav", "::Files\\Sounds\\CORKPOP.wav", "::Files\\Sounds\\DOG.wav", "::Files\\Sounds\\DRIVEBY.wav", "::Files\\Sounds\\DRUMROLL.wav", "::Files\\Sounds\\EXPLODE.wav", "::Files\\Sounds\\FINALBEL.wav", "::Files\\Sounds\\FROG.wav", "::Files\\Sounds\\GLASS.wav", "::Files\\Sounds\\GUNSHOT.wav", "::Files\\Sounds\\LASER.wav", "::Files\\Sounds\\LATNWHIS.wav", "::Files\\Sounds\\PIG.wav", "::Files\\Sounds\\RICOCHET.wav", "::Files\\Sounds\\RINGIN.wav", "::Files\\Sounds\\SIREN.wav", "::Files\\Sounds\\TRAIN.wav", "::Files\\Sounds\\UH_OH.wav", "::Files\\Sounds\\VERYGOOD.wav", "::Files\\Sounds\\WHOOSH.wav" }; //--- Names of graphical objects string sound_names[ARRAY_SIZE]= { "sound_button01","sound_button02", "sound_button03","sound_button04", "sound_button05","sound_button06", "sound_button07","sound_button08", "sound_button09","sound_button10", "sound_button11","sound_button12", "sound_button13","sound_button14", "sound_button15","sound_button16", "sound_button17","sound_button18", "sound_button19","sound_button20", "sound_button21","sound_button22", "sound_button23","sound_button24", "sound_button25","sound_button26" }; //--- Text displayed on graphical objects string sound_texts[ARRAY_SIZE]= { "ALERT","AHOOGA","APPLAUSE","BONK","CARBRAKE","CASHREG", "CLAP","CORKPOP","DOG","DRIVEBY","DRUMROLL","EXPLODE","FINALBEL", "FROG","GLASS","GUNSHOT","LASER","LATNWHIS","PIG", "RICOCHET","RINGIN","SIREN","TRAIN","UH_OH","VERYGOOD","WHOOSH" };
我们来编写一个函数 CreateButton(),它将在图像上创建具有指定属性的图形对象“按钮”:
//+------------------------------------------------------------------+ //| Creating the Button object | //+------------------------------------------------------------------+ void CreateButton(long chart_id, // chart id int sub_window, // window number string name, // object name string text, // displayed name ENUM_ANCHOR_POINT anchor, // anchor point ENUM_BASE_CORNER corner, // chart corner string font_name, // font int font_size, // font size color font_color, // font color color background_color, // background color color border_color, // border color int x_size, // width int y_size, // height int x_distance, // X-coordinate int y_distance, // Y-coordinate long z_order) // Z-order { //--- Creating an object if(ObjectCreate(chart_id,name,OBJ_BUTTON,sub_window,0,0)) { ObjectSetString(chart_id,name,OBJPROP_TEXT,text); // setting name ObjectSetString(chart_id,name,OBJPROP_FONT,font_name); // setting font ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color); // setting font color ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color); // setting background color ObjectSetInteger(chart_id,name,OBJPROP_BORDER_COLOR,border_color); // setting border color ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor); // setting anchor point ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner); // setting chart corner ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size); // setting font size ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size); // setting width X ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size); // setting height Y ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance); // setting X-coordinate ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance); // setting Y-coordinate ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false); // cannot select the object if FALSE ObjectSetInteger(chart_id,name,OBJPROP_STATE,false); // button state (clicked/unclicked) ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order); // higher/lower Z-order ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n"); // no tooltip if "\n" } }
为使其更加有趣,将随机选择每个按钮的颜色。要实现这一点,我们将编写一个简单的函数 - GetRandomColor():
//+------------------------------------------------------------------+ //| Returning a random color | //+------------------------------------------------------------------+ color GetRandomColor() { //--- Select a random color from 0 to 25 switch(MathRand()%26) { case 0 : return(clrOrange); break; case 1 : return(clrGold); break; case 2 : return(clrChocolate); break; case 3 : return(clrChartreuse); break; case 4 : return(clrLime); break; case 5 : return(clrSpringGreen); break; case 6 : return(clrMediumBlue); break; case 7 : return(clrDeepSkyBlue); break; case 8 : return(clrBlue); break; case 9 : return(clrSeaGreen); break; case 10 : return(clrRed); break; case 11 : return(clrSlateGray); break; case 12 : return(clrPeru); break; case 13 : return(clrBlueViolet); break; case 14 : return(clrIndianRed); break; case 15 : return(clrMediumOrchid); break; case 16 : return(clrCrimson); break; case 17 : return(clrMediumAquamarine); break; case 18 : return(clrDarkGray); break; case 19 : return(clrSandyBrown); break; case 20 : return(clrMediumSlateBlue); break; case 21 : return(clrTan); break; case 22 : return(clrDarkSalmon); break; case 23 : return(clrBurlyWood); break; case 24 : return(clrHotPink); break; case 25 : return(clrLightSteelBlue); break; //--- default : return(clrGold); } //--- return(clrGold); }
现在我们来编写一个函数,以将声音面板添加至图表 - SetSoundPanel():
//+------------------------------------------------------------------+ //| Adding the sound panel to the chart | //+------------------------------------------------------------------+ void SetSoundPanel() { int column_count =0; // Column counter int x_dist =10; // Indent from the left side of the chart int y_dist =15; // Indent from the top of the chart int x_size =100; // Button width int y_size =20; // Button height color button_color =clrNONE; // Button color //--- Set the objects for(int i=0; i<ARRAY_SIZE; i++) { //--- Increase the column counter column_count++; //--- Get the button color button_color=GetRandomColor(); //--- Draw a button CreateButton(0,0,sound_names[i],sound_texts[i], ANCHOR_LEFT_UPPER,CORNER_LEFT_UPPER,"Arial",8, clrWhite,button_color,button_color,x_size,y_size,x_dist,y_dist,1); //--- If two buttons have already been set in the same row if(column_count==2) { x_dist=10; // Move the X-coordinate to the initial position y_dist+=20; // Set the Y-coordinate for the next row column_count=0; // Zero out the counter } else //--- Set the X-coordinate for the next button x_dist+=x_size; } //--- Refresh the chart ChartRedraw(0); }
要从图表上删除面板,我们将使用下面提供的函数:
//+------------------------------------------------------------------+ //| Deleting the info panel | //+------------------------------------------------------------------+ void DeleteSoundPanel() { //--- Delete position properties and their values for(int i=0; i<ARRAY_SIZE; i++) DeleteObjectByName(name_sound_object[i]); //--- Redraw the chart ChartRedraw(); } //+------------------------------------------------------------------+ //| Deleting objects by name | //+------------------------------------------------------------------+ void DeleteObjectByName(string name) { //--- If the object is found if(ObjectFind(ChartID(),name)>=0) { //--- If an error occurred when deleting, print the relevant message if(!ObjectDelete(ChartID(),name)) Print("Error ("+IntegerToString(GetLastError())+") when deleting the object!"); } }
因此,当加载“EA 交易”时,面板将从 OnInit() 函数设置到图表上,并在删除“EA 交易”时通过 OnDeinit() 函数从图表上删除。
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ void OnInit() { //--- Set the sound panel SetSoundPanel(); } //+------------------------------------------------------------------+ //| Deinitialization function of the expert advisor | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Delete the sound panel DeleteSoundPanel(); }
现在,我们只需要实现与面板的交互,以便在按下某个按钮时播放相应的声音。为使其更加具有趣味性,我们将在按下一个声音面板按钮时更改按钮颜色。要实现这一点,我们将需要 ChangeColorsOnSoundPanel() 函数,其代码如下所示:
//+------------------------------------------------------------------+ //| Changing colors on the sound panel | //+------------------------------------------------------------------+ void ChangeColorsOnSoundPanel() { color clr=clrNONE; // Button color //--- Iterate over all buttons in a loop and change their color for(int i=0; i<ARRAY_SIZE; i++) { //--- Get the new color clr=GetRandomColor(); //--- Set the border color ObjectSetInteger(0,sound_names[i],OBJPROP_BGCOLOR,clr); //--- Set the background color ObjectSetInteger(0,sound_names[i],OBJPROP_BORDER_COLOR,clr); //--- Unclicked button ObjectSetInteger(0,sound_names[i],OBJPROP_STATE,false); //--- Refresh the chart ChartRedraw(0); //--- Wait for 20 ms (lag) Sleep(20); } }
最后,应将下述代码添加至 OnChartEvent() 函数:
//+------------------------------------------------------------------+ //| Event handler | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // Event identifier const long& lparam, // Parameter of the event of type long const double& dparam, // Parameter of the event of type double const string& sparam) // Parameter of the event of type string { //--- If there was an event of left-clicking on the object if(id==CHARTEVENT_OBJECT_CLICK) { //--- If the object name contains "sound_button" if(StringFind(sparam,"sound_button",0)>=0) { //--- Play the sound based on the object name // 5019 - ERR_FILE_NOT_EXIST - The file does not exist if(!PlaySound(GetSoundPath(sparam))) Print("Error: ",GetLastError()); //--- Change colors of all buttons ChangeColorsOnSoundPanel(); } } }
上述代码中高亮显示的字符串表示声音文件的位置已使用自定义 GetSoundPath() 函数传递至 PlaySound() 函数。GetSoundPath() 函数的代码如下所示:
//+------------------------------------------------------------------+ //| Returning sound file location by the object name | //+------------------------------------------------------------------+ string GetSoundPath(string object_name) { //--- Iterate over all sound panel objects in a loop for(int i=0; i<ARRAY_SIZE; i++) { //--- If the name of the object clicked in the chart // matches one of those available on the panel, return the file location if(object_name==name_sound_object[i]) return(path_sound_object[i]); } //--- return(""); }
现在,一切准备就绪。声音面板(该程序可以从本文的附件下载)将在“EA 交易”附加至图表时设置:
图 2. 图表上的声音面板
那么,声音文件的使用原理现已清楚。我们回到来自前文 “MQL5 细则手册:保存基于指定标准的“EA 交易”的优化结果”的“EA 交易”,并决定我们将在“EA 交易”中使用哪些声音。我们创建 Resources.mqh 并将其包含在“EA 交易”的主文件中。
//--- Include custom libraries #include "Include/Errors.mqh" #include "Include/Enums.mqh" #include "Include/Resources.mqh" #include "Include/TradeSignals.mqh" #include "Include/TradeFunctions.mqh" #include "Include/ToString.mqh" #include "Include/Auxiliary.mqh"
现在,我们为主交易事件选择文件。
//--- Sound files #resource "\\Files\\Sounds\\AHOOGA.WAV" // Error #resource "\\Files\\Sounds\\CASHREG.WAV" // Position opening/position volume increase/pending order triggering #resource "\\Files\\Sounds\\WHOOSH.WAV" // Pending order/Stop Loss/Take Profit setting/modification #resource "\\Files\\Sounds\\VERYGOOD.WAV" // Position closing at profit #resource "\\Files\\Sounds\\DRIVEBY.WAV" // Position closing at loss //--- Sound file location string SoundError = "::Files\\Sounds\\AHOOGA.WAV"; string SoundOpenPosition = "::Files\\Sounds\\CASHREG.WAV"; string SoundAdjustOrder = "::Files\\Sounds\\WHOOSH.WAV"; string SoundCloseWithProfit= "::Files\\Sounds\\VERYGOOD.WAV"; string SoundCloseWithLoss = "::Files\\Sounds\\DRIVEBY.WAV";
我还想说的是,除了用作资源的声音文件,您也可以在“EA 交易”中存储用作界面的 *.bmp 图像、文本文件甚至指标。MetaTrader 5 的 EA 现被视为功能完备的应用程序 - 这非常方便,您只需传递一个文件而不是多个文件。
我们继续。在外部参数中,我们需要添加 UseSound 参数以能够禁用声音:
//--- External parameters of the Expert Advisor input int NumberOfBars =2; // Number of one-direction bars sinput double Lot =0.1; // Lot input double TakeProfit =100; // Take Profit input double StopLoss =50; // Stop Loss input double TrailingStop =10; // Trailing Stop input bool Reverse =true; // Position reversal sinput bool UseSound =true; // Sound notifications
在 Include\Enums.mqh 中,我们为声音创建 ENUM_SOUNDS 枚举。
//--- Sounds enum ENUM_SOUNDS { SOUND_ERROR =0, // Error SOUND_OPEN_POSITION = 1, // Position opening/position volume increase/pending order triggering SOUND_ADJUST_ORDER = 2, // Stop Loss/Take Profit/pending order setting SOUND_CLOSE_WITH_PROFIT = 3, // Position closing at profit SOUND_CLOSE_WITH_LOSS = 4 // Position closing at loss };
自定义函数 PlaySoundByID() 将需要这些标识符。
//+------------------------------------------------------------------+ //| Playing sounds | //+------------------------------------------------------------------+ void PlaySoundByID(ENUM_SOUNDS id) { //--- If it is the real-time mode and sounds are enabled if(IsRealtime() && UseSound) { //--- Play the sound based on the identifier passed switch(id) { case SOUND_ERROR : PlaySound(SoundError); break; case SOUND_OPEN_POSITION : PlaySound(SoundOpenPosition); break; case SOUND_ADJUST_ORDER : PlaySound(SoundAdjustOrder); break; case SOUND_CLOSE_WITH_PROFIT : PlaySound(SoundCloseWithProfit); break; case SOUND_CLOSE_WITH_LOSS : PlaySound(SoundCloseWithLoss); break; } } }
在“EA 交易”执行交易操作期间,音效可通过从相应的交易函数调用 PlaySoundByID() 来播放。我们来看看这一点是如何在 OpenPosition() 函数中实现的:
//+------------------------------------------------------------------+ //| Opening a position | //+------------------------------------------------------------------+ void OpenPosition(double lot, ENUM_ORDER_TYPE order_type, double price, double sl, double tp, string comment) { //--- Set the magic number in the trading structure trade.SetExpertMagicNumber(0); //--- Set the slippage in points trade.SetDeviationInPoints(CorrectValueBySymbolDigits(10)); //--- The Instant Execution and Market Execution modes // *** Starting with build 803, Stop Loss and Take Profit *** // *** can be set upon opening a position in the SYMBOL_TRADE_EXECUTION_MARKET mode *** if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT || symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET) { //--- If the position failed to open if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) { //--- Play the error sound and print the relevant message PlaySoundByID(SOUND_ERROR); Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } //--- Otherwise play the position opening sound else PlaySoundByID(SOUND_OPEN_POSITION); } }
然而,如果一个仓位在“止损”、“获利”位通过手动或其他方式平仓,必须在 OnTrade() 函数中对该事件进行监控。要实现这一点,我们将编写另一个函数 SoundNotification(),它将负责必要的检查:如果交易的历史数据显示当前交易品种的新的交易具有 DEAL_ENTRY_OUT 或 DEAL_ENTRY_INOUT 标识符(完全/部分平仓或反向操作),程序将检查该交易平仓获利或亏损以及是否播放相应的声音。
//+------------------------------------------------------------------+ //| Sound notification | //+------------------------------------------------------------------+ void SoundNotification() { //--- If it is the real-time mode and sounds are enabled if(IsRealtime() && UseSound) { ulong ticket =0; // Deal ticket int total =0; // Total deals static ulong last_ticket =0; // Last ticket prior to this check //--- Get the complete history if(!HistorySelect(0,TimeCurrent()+1000)) return; //--- Get the number of deals in the obtained list total=HistoryDealsTotal(); //--- In the obtained list, iterate over all deals from the last one to the first one for(int i=total-1; i>=0; i--) { //--- If the deal ticket by its position in the list has been obtained if((ticket=HistoryDealGetTicket(i))>0) { //--- get the symbol of the deal GetHistoryDealProperties(ticket,D_SYMBOL); //--- If the symbol of the deal and the current symbol are the same if(deal.symbol==_Symbol) { //--- get the direction of the deal GetHistoryDealProperties(ticket,D_ENTRY); //--- If it is position closing, volume decrease or reversal if(deal.entry==DEAL_ENTRY_OUT || deal.entry==DEAL_ENTRY_INOUT) { //--- If the ticket of the current deal from the list (the last deal for the symbol) is equal to the previous ticket // or this is the initialization of the ticket of the last deal if(ticket==last_ticket || last_ticket==0) { //--- Save the ticket and exit last_ticket=ticket; return; } //--- Get the result of the deal GetHistoryDealProperties(ticket,D_PROFIT); //--- In case of profit if(deal.profit>=0) { //--- Profit sound PlaySoundByID(SOUND_CLOSE_WITH_PROFIT); //--- Save the ticket number last_ticket=ticket; return; } //--- In case of loss if(deal.profit<0) { //--- Loss sound PlaySoundByID(SOUND_CLOSE_WITH_LOSS); //--- Save the ticket number last_ticket=ticket; return; } } } } } } }
SoundNotification() 函数应位于 OnInit() 和 OnTrade() 函数中:
//+------------------------------------------------------------------+ //| Initialization | //+------------------------------------------------------------------+ int OnInit() { //--- Initialize the new bar CheckNewBar(); //--- Initialize tickets of the last deals for the symbol SoundNotification(); //--- Initialization completed successfully return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Monitoring trade events | //+------------------------------------------------------------------+ void OnTrade() { //--- Sound notification SoundNotification(); }
当修改追踪止损水平时,声音通知也被添加至 ModifyTrailingStop() 函数的末尾。
总结
就是这样。用于测试的所有文件都可在本文的附件中下载。说起终端的声音,我想提醒读者注意代码库中 CMIDI 名称下的一个有趣的解决方案(整型):它允许您在 MetaTrader 5 中播放 MIDI 文件。祝您好运!
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/748
注意: 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.




...
,例如,您建议的交易事件声音,它将合乎逻辑地提供具体的语音评论,包括利润值、杀戮值等,并提供建议和意见。
顾问必须有一天开始用正常的人类语言为我们提供建议......)。
...
这篇文章一如既往地举了一个简单的例子。例如,我喜欢FL Studio 11 程序。您可以合成任何声音。或者先录音(包括声音),然后进行高质量处理。
感谢您的文章。
我应该把所附程序放在哪里?放在 "脚本 "还是 "专家"?
顺便问一下,"脚本 "和 "专家 "有什么区别?OnStart 功能在脚本(将被拖到图表上)中有效吗?
我找不到 MT5 声音文件。我知道你给了位置,但我在文件夹里找不到。我可以把声音放到里面的任何地方,然后再找出来吗?
正确的文件夹是
C:\Program Files\platform folder\Sounds
(文件和文件夹 - 高级用户 - 入门 - MetaTrader 5 帮助)。
感谢您的文章。
我应该把所附程序放在哪里?放在 "脚本 "还是 "专家"?
顺便问一下,"脚本 "和 "专家 "有什么区别?OnStart 功能在脚本(将被拖到图表上)中有效吗?
在作者的文章中,请参阅"让我们创建一个智能交易系统......"。
因此,这是一个智能交易系统,而不是脚本。
脚本只在连接后运行一次。智能交易系统在每个刻度线(或定时器、事件等,取决于其代码中的特定标准功能)上运行。