MQL5 Cookbook: 开发多品种指标分析价格偏离·进阶篇
(2/3)· 1500 行指标拆成三份头文件,拖一下图表就能重算偏离,老手也常卡在缓存区配色
多品种背离指标的基础变量与运行限制
写多品种价格背离指标,第一步是把状态字符串和核心数组先声明好。下面这组全局变量里,msg_not_synchronized 用于提醒数据未同步,symbol_difference[] 和 inverse_difference[] 都按 SYMBOLS_COUNT 长度开路,分别存相对主图的价差和反转计算差值;divergence_price、divergence_time 则锁定背离起点。 指标不能在策略测试器里跑,这是硬约束。CheckTesterMode() 用 MQLInfoInteger 同时判断 MQL_TESTER、MQL_VISUAL_MODE、MQL_OPTIMIZATION 三个标志,任一为真就 Comment 提示并 return false。实盘加载前先在 MT5 里点开「专家顾问测试」面板验证,若看到那句 not intended to be used in Strategy Tester,说明编译逻辑已生效。 K 线配色交给 SetBarsColors() 处理。它通过 ChartSetInteger(0, CHART_COLOR_CHART_UP, color_bar_up) 等调用直接改当前图表(句柄 0)的阳线、蜡烛体、折线色;若 TwoColor 开关打开,再补设 CHART_COLOR_CHART_DOWN 和 bear candlestick 的体色。外汇与贵金属波动剧烈、杠杆风险高,这类视觉改写只辅助读图,不替代仓位管理。
class="type">class="kw">string msg_not_synchronized ="Unsynchronized data! Please wait..."; class="type">class="kw">string msg_load_data =""; class="type">class="kw">string msg_sync_update =""; class="type">class="kw">string msg_last =""; class=class="str">"cmt">//--- ENUM_TIMEFRAMES timeframe_start_point =Period(); class=class="str">"cmt">// Timeframe for the price divergence starting point class="type">class="kw">datetime first_period_time =NULL; class=class="str">"cmt">// Time of the first specified period on chart class="type">class="kw">double divergence_price =class="num">0.0; class=class="str">"cmt">// Price of the price divergence starting point class="type">class="kw">datetime divergence_time =NULL; class=class="str">"cmt">// Time of the price divergence starting point class="type">class="kw">double symbol_difference[SYMBOLS_COUNT]; class=class="str">"cmt">// Difference in price relative to the current symbol class="type">class="kw">double inverse_difference[SYMBOLS_COUNT]; class=class="str">"cmt">// Difference that is formed when calculating inversion class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Checks if indicator is used in Strategy Tester | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CheckTesterMode() { class=class="str">"cmt">//--- Report that indicator is not intended to be used in Strategy Tester if(MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_VISUAL_MODE) || MQLInfoInteger(MQL_OPTIMIZATION)) { Comment("Currently, the <- "+MQLInfoString(MQL_PROGRAM_NAME)+" -> indicator is not intended to be used in Strategy Tester!"); class="kw">return(false); } class=class="str">"cmt">//--- class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Sets colors for the current symbol bars | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void SetBarsColors() { class=class="str">"cmt">//--- Color for the up bar, shadows and body borders of bull candlesticks ChartSetInteger(class="num">0,CHART_COLOR_CHART_UP,color_bar_up); class=class="str">"cmt">//--- Body class="type">color of a bull candlestick ChartSetInteger(class="num">0,CHART_COLOR_CANDLE_BULL,color_bar_up); class=class="str">"cmt">//--- Line chart class="type">color and class="type">color of "Doji" Japanese candlesticks ChartSetInteger(class="num">0,CHART_COLOR_CHART_LINE,color_bar_up); class=class="str">"cmt">//--- For two-class="type">color mode if(TwoColor) { class=class="str">"cmt">//--- Color for the down bar, shadows and body borders of bear candlesticks ChartSetInteger(class="num">0,CHART_COLOR_CHART_DOWN,color_bar_down); class=class="str">"cmt">//--- Body class="type">color of a bear candlestick
「起点周期与参数校验的落地逻辑」
指标初始化时,先根据起点模式选定参考周期:月线对应 PERIOD_MN1,周线 PERIOD_W1,日线 PERIOD_D1,小时线 PERIOD_H1;若用户选了垂直线模式,则直接跳过周期绑定。 CheckInputParameters 会拦掉一个常见误用——当当前图表周期秒数大于等于起点周期秒数(PeriodSeconds() >= PeriodSeconds(timeframe_start_point))时,向终端打印并 Comment 提示,返回 false 终止加载。也就是说,挂 H1 图却把起点设成 HOUR,指标起不来。 InitArrays 负责把 limit_time、symbol_difference、inverse_difference 等数组清零或置空,再按 SYMBOLS_COUNT 循环把每个品种的 buffer_data[s].open 填成 EMPTY_VALUE,避免残留数据污染首根K线计算。 双色关闭时的配色分支也在这里:下跌K线的影线、边框与实体都指向 color_bar_up,等于把空头蜡烛画成多头色,回测或肉眼复盘时要留意这种反直觉设置。
ChartSetInteger(class="num">0,CHART_COLOR_CANDLE_BEAR,color_bar_down); } class=class="str">"cmt">//--- If two-class="type">color mode is turned off else { class=class="str">"cmt">//--- Color for the down bar, shadows and body borders of bear candlesticks ChartSetInteger(class="num">0,CHART_COLOR_CHART_DOWN,color_bar_up); class=class="str">"cmt">//--- Body class="type">color of a bear candlestick ChartSetInteger(class="num">0,CHART_COLOR_CANDLE_BEAR,color_bar_up); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Identifies timeframe for the price starting point mode | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void InitStartPointTF() { class=class="str">"cmt">//--- Exit if vertical line mode is selected if(StartPriceDivergence==VERTICAL_LINE) class="kw">return; class=class="str">"cmt">//--- Otherwise define the timeframe class="kw">switch(StartPriceDivergence) { case MONTH : timeframe_start_point=PERIOD_MN1; class="kw">break; case WEEK : timeframe_start_point=PERIOD_W1; class="kw">break; case DAY : timeframe_start_point=PERIOD_D1; class="kw">break; case HOUR : timeframe_start_point=PERIOD_H1; class="kw">break; } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Checks input parameters for correctness | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CheckInputParameters() { class=class="str">"cmt">//--- For all other modes except the &class="macro">#x27;Vertical Line&class="macro">#x27; if(StartPriceDivergence!=VERTICAL_LINE) { class=class="str">"cmt">//--- If the current period is greater than or equal to the specified period of the price divergence starting point, report of it and exit if(PeriodSeconds()>=PeriodSeconds(timeframe_start_point)) { Print("Current timeframe should be less than one specified in the Start Price Divergence parameter!"); Comment("Current timeframe should be less than one specified in the Start Price Divergence parameter!"); class="kw">return(false); } } class=class="str">"cmt">//--- class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| First initialization of arrays | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void InitArrays() { ArrayInitialize(limit_time,NULL); ArrayInitialize(symbol_difference,class="num">0.0); ArrayInitialize(inverse_difference,class="num">0.0); ArrayInitialize(series_first_date,NULL); ArrayInitialize(series_first_date_last,NULL); class=class="str">"cmt">//--- for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) { ArrayInitialize(buffer_data[s].open,EMPTY_VALUE);
◍ 缓冲区与多品种初始化的底层接线
多品种指标在 MT5 里先把每个品种的 OHLC 缓冲区和颜色索引全部灌成 EMPTY_VALUE,否则历史不足的周期会画出 0 轴附近的脏线。外层两层循环对 SYMBOLS_COUNT 个品种、每品种 4 个价格数组加 1 个颜色数组做 ArrayInitialize,是避免图形撕裂的基础动作。 InitSymbolNames 把 Symbol02~Symbol06 共 5 个外部品种经 AddSymbolToMarketWatch 写入 symbol_names 数组,InitInverse 则同步装入 Inverse02~Inverse06 的反向开关。这两步决定了后面绘图时取的是直盘报价还是倒置报价,贵金属与交叉盘混排时尤其要核对。 SetIndicatorProperties 里按 DrawType 分流缓冲区:LINE 模式只绑 close 一个缓冲,省资源;BARS / CANDLES 模式用静态计数器 buffer_number 顺序绑 open/high/low/close 各一个 INDICATOR_DATA 再加一个 INDICATOR_COLOR_INDEX,每品种吃掉 5 个句柄。开 MT5 把 SYMBOLS_COUNT 改成你实际品种数,若超出 5 却没扩数组,绑定会越界报错。
ArrayInitialize(buffer_data[s].high,EMPTY_VALUE); ArrayInitialize(buffer_data[s].low,EMPTY_VALUE); ArrayInitialize(buffer_data[s].close,EMPTY_VALUE); ArrayInitialize(buffer_data[s].icolor,EMPTY_VALUE); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Initializes array of symbols | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void InitSymbolNames() { symbol_names[class="num">0]=AddSymbolToMarketWatch(Symbol02); symbol_names[class="num">1]=AddSymbolToMarketWatch(Symbol03); symbol_names[class="num">2]=AddSymbolToMarketWatch(Symbol04); symbol_names[class="num">3]=AddSymbolToMarketWatch(Symbol05); symbol_names[class="num">4]=AddSymbolToMarketWatch(Symbol06); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Initializes array of inversions | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void InitInverse() { inverse[class="num">0]=Inverse02; inverse[class="num">1]=Inverse03; inverse[class="num">2]=Inverse04; inverse[class="num">3]=Inverse05; inverse[class="num">4]=Inverse06; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Sets indicator properties | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void SetIndicatorProperties() { class=class="str">"cmt">//--- Set the class="type">short name IndicatorSetString(INDICATOR_SHORTNAME,indicator_shortname); class=class="str">"cmt">//--- Set the number of decimal digits IndicatorSetInteger(INDICATOR_DIGITS,_Digits); class=class="str">"cmt">//--- In the &class="macro">#x27;Line&class="macro">#x27; mode we need only one buffers that displays the open price if(DrawType==LINE) { for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) SetIndexBuffer(s,buffer_data[s].close,INDICATOR_DATA); } class=class="str">"cmt">//--- In other modes we use all prices for drawing class=class="str">"cmt">// bars/candlesticks and additional buffer for the two-class="type">color mode else if(DrawType==BARS || DrawType==CANDLES) { for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) { class="kw">static class="type">int buffer_number=class="num">0; SetIndexBuffer(buffer_number,buffer_data[s].open,INDICATOR_DATA); buffer_number++; SetIndexBuffer(buffer_number,buffer_data[s].high,INDICATOR_DATA); buffer_number++; SetIndexBuffer(buffer_number,buffer_data[s].low,INDICATOR_DATA); buffer_number++; SetIndexBuffer(buffer_number,buffer_data[s].close,INDICATOR_DATA); buffer_number++; SetIndexBuffer(buffer_number,buffer_data[s].icolor,INDICATOR_COLOR_INDEX); buffer_number++; } }
多品种绘图标签与图表模式的绑定逻辑
在 MT5 多品种指标里,绘图模式直接决定标签怎么写、柱子怎么画。LINE 模式只取收盘价,所以给每个品种缓冲区设的 PLOT_LABEL 就是「品种名,Close」;而 BARS 和 CANDLES 要把开高低收全甩进数据窗,标签用分号隔开四个价格字段。 绘图类型靠 PlotIndexSetInteger 逐个缓冲区指派:DRAW_LINE、DRAW_COLOR_BARS、DRAW_COLOR_CANDLES 三选一,同时用 ChartSetInteger(0,CHART_MODE,...) 把主图自身也切成对应样式,否则会出现指标画蜡烛、主图却是线图的错位。 线宽统一压成 1,LINE 模式下再按 line_colors 数组上色;最后循环里只给 symbol_names 不等于空字符串的缓冲区开 PLOT_SHOW_DATA,避免废符号污染数据窗。外汇与贵金属波动剧烈、杠杆高风险,参数改动后请在策略测试器用历史数据验证显示逻辑。
class=class="str">"cmt">//--- Set labels for the current timeframe class=class="str">"cmt">// In the &class="macro">#x27;Line&class="macro">#x27; mode only opening price is used if(DrawType==LINE) { for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) PlotIndexSetString(s,PLOT_LABEL,symbol_names[s]+",Close"); } class=class="str">"cmt">//--- In other modes all prices of bars/candlesticks class=class="str">"cmt">// ";" is used as a separator else if(DrawType==BARS || DrawType==CANDLES) { for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) { PlotIndexSetString(s,PLOT_LABEL, symbol_names[s]+",Open;"+ symbol_names[s]+",High;"+ symbol_names[s]+",Low;"+ symbol_names[s]+",Close"); } } class=class="str">"cmt">//--- Set the type of lines for indicator buffers class=class="str">"cmt">//--- Line if(DrawType==LINE) for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_LINE); class=class="str">"cmt">//--- Bars if(DrawType==BARS) for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_COLOR_BARS); class=class="str">"cmt">//--- Candlesticks if(DrawType==CANDLES) for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_COLOR_CANDLES); class=class="str">"cmt">//--- Set the type of lines for data of current symbol class=class="str">"cmt">//--- Line if(DrawType==LINE) ChartSetInteger(class="num">0,CHART_MODE,CHART_LINE); class=class="str">"cmt">//--- Bars if(DrawType==BARS) ChartSetInteger(class="num">0,CHART_MODE,CHART_BARS); class=class="str">"cmt">//--- Candlesticks if(DrawType==CANDLES) ChartSetInteger(class="num">0,CHART_MODE,CHART_CANDLES); class=class="str">"cmt">//--- Set the line width for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) PlotIndexSetInteger(s,PLOT_LINE_WIDTH,class="num">1); class=class="str">"cmt">//--- Set the line class="type">color for the &class="macro">#x27;Line&class="macro">#x27; mode if(DrawType==LINE) for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) PlotIndexSetInteger(s,PLOT_LINE_COLOR,line_colors[s]); class=class="str">"cmt">//--- Display data in Data Window only for existing symbols for(class="type">int s=class="num">0; s<SYMBOLS_COUNT; s++) { if(symbol_names[s]!=empty_symbol) PlotIndexSetInteger(s,PLOT_SHOW_DATA,true);
「初始化里如何埋好背离起点」
指标启动阶段就把背离起点画好,能省掉实盘里反复手动标线的麻烦。OnInit 里先拦掉策略测试器之外的非法环境,再依次跑颜色、起点周期、参数校验,最后挂 1 秒毫秒定时器 EventSetMillisecondTimer(1000) 保活刷新。 SetDivergenceLine 的逻辑很直接:当模式是 VERTICAL_LINE 且图上还没这根线(ObjectFind 返回负值),就用 CreateVerticalLine 在 TimeCurrent()+PeriodSeconds() 处落一根绿黄色竖线;若不是该模式,则顺手 DeleteObjectByName 清掉旧对象,避免不同模式切换留垃圾。 CheckAvailableData 给数据等待留了 100 次尝试上限(attempts=100),对多品种同时拉历史的外汇/贵金属指标来说,这能避免在流动性差的品种上卡死初始化。MT5 里开多符号背离指标时,建议先把 SYMBOLS_COUNT 和这个尝试次数对着经纪商可见品种数调一遍。 外汇与贵金属波动剧烈、杠杆风险高,竖线仅作起点参照,不代表任何方向确定性。
else PlotIndexSetInteger(s,PLOT_SHOW_DATA,false); } class=class="str">"cmt">//--- Empty value for plotting where nothing will be drawn for(class="type">int s=class="num">0;s<SYMBOLS_COUNT; s++) PlotIndexSetDouble(s,PLOT_EMPTY_VALUE,EMPTY_VALUE); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Sets vertical line for price divergence starting point | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void SetDivergenceLine() { class=class="str">"cmt">//--- If there is no vertical line yet, set it if(StartPriceDivergence==VERTICAL_LINE && ObjectFind(class="num">0,start_price_divergence)<class="num">0) class=class="str">"cmt">//--- Place a vertical line on the true bar CreateVerticalLine(class="num">0,class="num">0,TimeCurrent()+PeriodSeconds(),start_price_divergence, class="num">2,STYLE_SOLID,clrGreenYellow,true,true,false,"","\n"); class=class="str">"cmt">//--- For all other modes except the &class="macro">#x27;Vertical Line&class="macro">#x27; if(StartPriceDivergence!=VERTICAL_LINE) DeleteObjectByName(start_price_divergence); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Custom indicator initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- Check if indicator is currently being used in Strategy Tester if(!CheckTesterMode()) class="kw">return(INIT_FAILED); class=class="str">"cmt">//--- Set the class="type">color for bars/candlesticks SetBarsColors(); class=class="str">"cmt">//--- Define the timeframe for the price divergence starting point InitStartPointTF(); class=class="str">"cmt">//--- Check input parameters for correctness if(!CheckInputParameters()) class="kw">return(INIT_PARAMETERS_INCORRECT); class=class="str">"cmt">//--- Set the timer at class="num">1-second intervals EventSetMillisecondTimer(class="num">1000); class=class="str">"cmt">//--- Set the font to be displayed on the canvas canvas.FontSet(font_name,font_size,FW_NORMAL); class=class="str">"cmt">//--- Initialization of arrays InitArrays(); class=class="str">"cmt">//--- Initialize the array of symbols InitSymbolNames(); class=class="str">"cmt">//--- Initialize the array of inversions InitInverse(); class=class="str">"cmt">//--- Set indicator properties SetIndicatorProperties(); class=class="str">"cmt">//--- Set vertical line of the price divergence start SetDivergenceLine(); class=class="str">"cmt">//--- Clear the comment Comment(""); class=class="str">"cmt">//--- Refresh the chart ChartRedraw(); class=class="str">"cmt">//--- Initialization completed successfully class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Checks the amount of available data for all symbols | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CheckAvailableData() { class="type">int attempts=class="num">100; class=class="str">"cmt">//--- for(class="type">int s=class="num">0;s<SYMBOLS_COUNT; s++) { class=class="str">"cmt">//--- If this symbol is available if(symbol_names[s]!=empty_symbol) {
◍ 数据齐了才能画背离线
MT5 里跨周期或换品种读取历史时,最容易踩的坑是:终端还没把全部 bar 拉下来,指标就急着算背离,结果前面几百根 K 线时间是空的。下面这段逻辑先摸清「终端里这个品种当前周期到底存了多少根」,再决定要不要继续。 datetime time[]; // 装时间数组,用来核对实际拷贝到的 bar 数 int total_period_bars = 0; // 当前周期应有的总 bar 数 datetime terminal_first_date = NULL; // 终端里该周期最早一条数据的日期 // 先问终端:这个周期最早数据是哪天 time_terminal_first_date=(datetime)SeriesInfoInteger(symbol_names[s],Period(),SERIES_TERMINAL_FIRSTDATE); // 从最早那天算到此刻,共有多少根 total_period_bars=Bars(symbol_names[s],Period(),terminal_first_date,TimeCurrent()); // 尝试多次拷贝,直到拷贝到的数量够为止 for(int i=0; i<attempts; i++) { if(CopyTime(symbol_names[s],Period(),0,total_period_bars,time)) { if(ArraySize(time)>=total_period_bars) break; } } // 一根没拷到或数量不够,打提示并退出,等下一轮重来
| if(ArraySize(time)==0 | ArraySize(time)<total_period_bars) |
|---|
{ msg_last=msg_prepare_data; ShowCanvasMessage(msg_prepare_data); OC_prev_calculated=0; return(false); } 外汇和贵金属行情在跳空或刚开盘时,服务器推送延迟会让 Bars() 返回的值比真实可见 K 线少几根,概率不低。把 attempts 设成 3~5 次重试,比一次性失败更稳。 如果 StartPriceDivergence 设成 VERTICAL_LINE,数据齐了直接返回 true 去画竖线;否则走另一段:用 SeriesInfoInteger(Symbol(),Period(),SERIES_FIRSTDATE) 拿本图表周期首根日期,同样套一层重试循环。开 MT5 把这段粘进指标 OnInit 之前跑一遍,能在图表左上角看到是否卡在「准备数据」状态。
class="type">class="kw">datetime time[]; class=class="str">"cmt">// Array for checking the number of bars class="type">int total_period_bars =class="num">0; class=class="str">"cmt">// Number of bars of the current period class="type">class="kw">datetime terminal_first_date =NULL; class=class="str">"cmt">// First date of the current time frame data available in the terminal class=class="str">"cmt">//--- Get the first date of the current time frame data in the terminal terminal_first_date=(class="type">class="kw">datetime)SeriesInfoInteger(symbol_names[s],Period(),SERIES_TERMINAL_FIRSTDATE); class=class="str">"cmt">//--- Get the number of available bars from the date specified total_period_bars=Bars(symbol_names[s],Period(),terminal_first_date,TimeCurrent()); class=class="str">"cmt">//--- Check the readiness of bar data for(class="type">int i=class="num">0; i<attempts; i++) { class=class="str">"cmt">//--- Copy the specified amount of data if(CopyTime(symbol_names[s],Period(),class="num">0,total_period_bars,time)) { class=class="str">"cmt">//--- If the required amount has been copied, terminate the loop if(ArraySize(time)>=total_period_bars) class="kw">break; } } class=class="str">"cmt">//--- If the amount of data copied is not sufficient, one more attempt is required if(ArraySize(time)==class="num">0 || ArraySize(time)<total_period_bars) { msg_last=msg_prepare_data; ShowCanvasMessage(msg_prepare_data); OC_prev_calculated=class="num">0; class="kw">return(false); } } } class=class="str">"cmt">//--- Exit if current mode is vertical line of the price divergence starting point if(StartPriceDivergence==VERTICAL_LINE) class="kw">return(true); else { class="type">class="kw">datetime time[]; class=class="str">"cmt">// Array for checking the number of bars class="type">int total_period_bars =class="num">0; class=class="str">"cmt">// Number of bars of the current period class="type">class="kw">datetime terminal_first_date =NULL; class=class="str">"cmt">// First date of the current time frame data available in the terminal class=class="str">"cmt">//--- Get the first date of the current time frame data in the terminal for(class="type">int i=class="num">0; i<attempts; i++) if((terminal_first_date=(class="type">class="kw">datetime)SeriesInfoInteger(Symbol(),Period(),SERIES_FIRSTDATE))>class="num">0) class="kw">break; class=class="str">"cmt">//--- Get the number of available bars from the date specified