外观
调试
约 19413 字大约 65 分钟
简介
TradingVue的Mine编辑器与图表界面紧密集成,为Mine Script®代码提供了高效的交互式调试环境。脚本可在图表内外多个位置生成动态结果,程序员可利用这些结果优化脚本行为并确保所有功能按预期工作。
当程序员掌握检测脚本编写过程中各类行为的恰当技巧时,就能快速彻底地识别和解决代码中的潜在问题,从而获得更顺畅的整体编码体验。本页介绍了使用Mine时最便捷的代码调试方法。
布局概览
Mine脚本可通过多种方式输出结果,程序员可利用其中任何一种进行调试。
plot*()系列函数可在图表面板、脚本状态行、价格(y轴)刻度以及数据窗口中显示结果,为数值和条件值的调试提供简单便捷的途径:

Mine Script®
已复制
请注意:
- 仅当在图表"状态行"设置的"指标"部分中启用"数值"复选框时,脚本状态行输出才会显示。
- 仅当在图表"刻度与线型"设置的"指标与金融产品"下拉菜单中启用相应选项时,价格刻度才会显示绘图数值或名称。
bgcolor()函数可在脚本面板背景中显示颜色,而barcolor()函数可更改主图表K线或蜡烛的颜色。这两个函数为条件可视化提供了简单方法:

Mine Script®
已复制
Mine的绘图类型(线条、方框、多段线、标签)可在脚本面板中生成图形。虽然它们不会在状态栏或数据窗口等其他位置返回结果,但为直接在图表上检查数值、条件和字符串提供了灵活的可选方案:

Mine Script®
已复制
log.*()函数可生成Mine日志结果。每次脚本调用这些函数时,都会在Mine日志面板中记录一条消息,同时附带时间戳和导航选项,用于定位触发日志的具体时间、图表K线及代码行:

Mine Script®
已复制
开发者可根据处理的数据类型和结构,选用上述任意一种或组合多种方法来建立适合自身需求和偏好的调试流程。请参阅以下章节获取各种调试技术的详细说明。
数值处理
在Mine Script中编写代码时,数值处理不可避免。因此,为确保脚本按预期工作,掌握如何检查其接收和计算的数值(整型和浮点型)至关重要。
绘制数值
检查脚本数值最直接的方法之一是使用plot*()函数,这些函数可以在图表上以图形方式显示结果,并在脚本状态行、价格刻度和数据窗口中显示格式化数字。plot*()函数显示结果的位置取决于display参数,其默认值为display.all。
以下示例使用plot()函数显示内置时间变量在图表时间框架内测量的一根柱的数值变化(例如,在“日线”图表上绘制值为1表示当前柱与前一根柱的开盘时间相差一天)。检查该序列有助于识别图表数据中的时间间隔,这对设计基于时间的指标时是有用的信息。
由于我们未指定display参数,该函数使用display.all,这意味着它将在所有可能的位置显示数据,如下所示:

Mine Script®
已复制
需注意:
- 脚本状态行和数据窗口中显示的数字反映图表光标所在位置的绘制值。当鼠标指针未悬停在图表上时,这些区域将显示最新柱的值。
- 价格刻度中的数字反映可见图表上最新可用值。
不影响刻度
在脚本中调试多个数值时,程序员可能希望在不干扰价格刻度或使图表窗格中的视觉输出杂乱无章的情况下检查这些值,因为扭曲的刻度和重叠的绘图可能使结果评估更加困难。
一种在不向图表窗格添加更多视觉元素的情况下检查数值的简单方法是将脚本plot*()调用中的显示值更改为其他display.*变量或使用它们的表达式。
让我们看一个实际示例。这里我们起草了以下脚本,通过将权重乘以收盘值的总和除以权重序列的总和来计算自定义加权移动平均:

Mine Script®
已复制
假设我们希望检查平均计算中使用的变量以理解和微调结果。如果我们使用plot()在所有位置显示脚本的权重、分子和分母,由于每个变量具有完全不同的刻度,我们将难以在图表上轻松识别平均线:

Mine Script®
已复制
虽然我们可以通过脚本设置中的“样式”选项卡隐藏单个绘图,但这样做也会阻止我们在任何其他位置检查结果。要同时查看变量值并保持图表刻度不变,我们可以更改调试绘图中的显示值。
以下版本在调试plot()调用中包含debugLocations变量,其值为display.all - display.pane,以指定除图表窗格外的所有位置都将显示结果。现在我们可以检查计算值而不会产生额外的视觉杂乱:

Mine Script®
已复制
从局部作用域
脚本的局部作用域是条件结构、函数和方法内缩进的代码段。当处理在这些作用域内声明的变量时,直接使用plot*()函数显示其值将无效,因为绘图仅适用于字面量和全局变量。
要使用绘图显示局部变量的值,可以将其结果赋值给全局变量,并将该变量传递给plot*()调用。
例如,该脚本计算在lengthInput周期内收盘价的历史最大和最小变动值。它使用if结构声明局部change变量,并每lengthInput根柱更新全局变量maxChange和minChange:

Mine Script®
已复制
假设我们希望通过绘图检查change变量的历史值。虽然无法直接绘制该变量(因为脚本在局部作用域中声明它),但我们可以将其值赋给另一个全局变量以用于plot*()函数。
下面我们在全局作用域中添加了初始值为na的debugChange变量,脚本在if结构中使用局部change变量重新为其赋值。现在,我们可以通过plot()函数使用debugChange变量查看可用change值的历史记录:

Mine Script®
已复制
需注意:
- 脚本在调试绘图中使用plot.style_circles样式,该样式不会像默认样式那样跨过na值进行桥接。
- 当最右侧可见柱的绘制值为na时,价格刻度中的数字表示该柱之前最新的非na值(若存在)。
使用绘图
另一种以图形方式检查脚本数值历史的方法是使用Mine的绘图类型,包括线条、方框、折线和标签。
虽然Mine绘图仅在图表窗格中显示结果,但脚本可以从局部作用域(包括函数和方法的作用域)创建它们(详见调试函数章节了解更多信息)。此外,脚本可以将绘图定位在任何可用的图表位置,与当前bar_index无关。
例如,让我们重新审视上一节的“周期性变化”脚本。假设我们希望在不使用绘图的情况下检查局部change变量的历史值。在这种情况下,我们可以避免声明单独的全局变量,而是直接从if结构的局部作用域创建绘图对象。
以下脚本是之前脚本的修改版本,它使用方框来可视化change变量的行为。在if结构的作用域内,它调用box.new()创建一个从lengthInput根柱前到当前bar_index的方框:

Mine Script®
已复制
需注意:
- 脚本在indicator()函数中包含
max_boxes_count = 500,这允许其在图表上显示最多500个方框。 - 我们在box.new()函数中使用
math.max(change, 0.0)和math.min(change, 0.0)作为顶部和底部值。 - box.new()调用包含
str.tostring(change)作为文本参数,以在每个方框绘图中显示change变量“浮点”值的“字符串”表示形式。请参阅下文字符串章节的相关部分以了解有关使用字符串表示数据的更多信息。
有关使用方框和其他相关绘图类型的更多信息,请参阅用户手册的线条和方框页面。
条件
在Mine中创建的许多脚本涉及声明和评估条件以控制特定的脚本操作,例如触发不同的计算模式、视觉效果、信号、警报、策略订单等。因此,必须了解如何检查脚本使用的条件以确保正确执行。
注意
本节讨论基于图表视觉效果的调试技术。要了解有关条件记录的功能,请参阅下文的Mine日志章节。
作为数值
调试脚本条件的一种可能方法是基于条件定义数值,这允许程序员使用数值方法进行检查,例如前一节中概述的方法。
让我们看一个简单示例。该脚本计算ohlc4价格与lengthInput周期移动平均线之间的比率。它将条件赋值给priceAbove变量,当比率值超过1时(即价格高于平均线)返回true。
为检查条件出现的情况,我们创建了debugValue变量,该变量被赋值为使用三元运算符?:的表达式结果:当priceAbove为true时返回1,否则返回0。脚本在所有可用位置绘制该变量的值:

Mine Script®
已复制
需注意:
- 使用数字表示“布尔”值还允许脚本通过plotshape()和plotchar()在特定y轴位置显示条件形状或字符,并有助于使用plotarrow()进行条件调试。详见下一节以了解更多信息。
绘制条件形状
plotshape()和plotchar()函数为调试条件提供了实用功能,它们可在包含true或非na序列参数时在绝对或相对图表位置绘制形状或字符。
这些函数还可在脚本状态行和数据窗口中显示序列的数值表示形式,这意味着它们也有助于调试数值。我们将在技巧章节展示使用这些函数调试数值的简单实用方法。
绘图在图表上的位置取决于location参数,其默认值为location.abovebar。
注意
当使用location.abovebar或location.belowbar时,该函数将形状/字符相对于主图表价格进行定位。如果脚本在单独的图表窗格中绘制其数值,我们建议使用其他定位选项进行调试,以避免影响窗格的刻度。
让我们使用这些函数检查一个条件。以下脚本计算长度为lengthInput的RSI指标,并声明crossBelow变量,其值为当RSI下穿30时返回true的条件结果。脚本调用plotshape()在每次条件发生时在窗格顶部附近显示圆形:

Mine Script®
已复制
需注意:
- 当
crossBelow为true时,状态行和数据窗口显示值为1;当其为false时显示值为0。
假设我们希望将形状显示在精确位置而非相对于图表窗格的位置。我们可以在plotshape()调用中使用条件数值和location.absolute来实现此目的。
在此示例中,我们修改了之前的脚本,创建了debugNumber变量,该变量在crossBelow为true时返回rsi值,否则返回na。plotshape()函数使用此新变量作为其序列参数,并使用location.absolute作为其位置参数:

Mine Script®
已复制
需注意:
- 由于我们向函数传递了数值序列,条件绘图现在会在状态行和数据窗口中显示
debugNumber的值,而不是1或0。 - 另一种便捷的调试条件是使用plotarrow()。该函数在序列参数非零且非na时绘制相对于主图表价格的箭头,每个箭头的长度随提供的序列值变化。与plotshape()和plotchar()类似,plotarrow()也可以在状态行和数据窗口中显示数值结果。
注意
由于此函数始终将箭头定位相对于主图表价格,我们建议仅在脚本占据主图表窗格时使用它,以避免干扰其他窗格的刻度。
此示例展示了使用plotarrow()检查crossBelow条件的另一种方法。在此版本中,我们在indicator()函数中将overlay设置为true,并添加了plotarrow()调用来可视化条件值。本示例中的debugNumber测量每次条件发生时rsi低于30的幅度:

Mine Script®
已复制
请注意:
- 我们在
rsi的 plot() 中将显示值设置为 display.data_window 以保持图表比例。 - 要详细了解 plotshape()、plotchar() 和 plotarrow(),请参阅本手册的文本和形状页面。
条件颜色
在 Mine 中直观呈现条件的优雅方式是创建根据真假状态返回颜色值的表达式,因为脚本可使用它们来控制绘图对象的外观或 plot*()、fill()、bgcolor() 或 barcolor() 调用的结果。
注意
与 plot*() 函数一样,脚本只能从全局范围调用 fill()、bgcolor() 和 barcolor(),并且这些函数不能接受任何局部变量。
例如,此脚本计算 lengthInput 根柱上的收盘价变化,并声明两个“布尔”变量以识别价格变化为正或负的情况。
该脚本使用这些“布尔”值作为三元表达式中的条件来分配三个“颜色”变量的值,然后将这些变量用作 fill()、bgcolor() 和 barcolor() 中的颜色参数以调试结果:

Mine Script®
已复制
请注意:
- barcolor() 函数始终为主图表K线着色,无论脚本是否位于其他图表窗格中,且仅当K线可见时图表才会显示结果。
有关颜色处理、填充绘图、高亮背景和K线着色的更多信息,请参阅颜色、填充、背景和k线着色页面。
使用绘图
Mine Script 的绘图类型提供了灵活的方式来可视化图表上的条件,尤其当条件位于局部作用域内时。
请考虑以下脚本,它计算一个带有平滑参数(alpha)的自定义过滤器,该参数在 if 结构内根据近期成交量条件改变其值:

Mine Script®
已复制
假设我们想要检查控制 alpha 值的条件。有多种方法可以通过图表视觉元素来完成此任务,但某些方法需要更多代码和谨慎处理。
例如,要使用绘制的形状或背景颜色来可视化 if 结构的条件,我们必须在全局作用域中创建额外的变量或表达式以供 plot*() 或 bgcolor() 函数访问。
或者,我们可以使用绘图类型来简洁地可视化这些条件,而无需这些额外步骤。
以下是对先前脚本的修改,它在条件结构的特定分支中调用 label.new(),每当这些分支执行时在图表上绘制标签。这些简单的更改使我们能够在图表上识别这些条件,而无需太多额外代码:

Mine Script®
已复制
请注意:
- 我们在
alpha重新赋值表达式之前添加了 label.new() 调用,因为 if 结构中每个分支的返回类型必须匹配。 - indicator() 函数包含
max_labels_count = 500以指定脚本在图表上最多可显示500个标签。
复合与嵌套条件
当程序员需要识别多个条件同时发生的情况时,可以通过逻辑运算符(and、or)聚合单个条件来构建复合条件。
例如,这行代码展示了一个 compoundCondition 变量,仅当 condition1 与 condition2 或 condition3 其中之一同时成立时返回 true:
Mine Script®
已复制
用户也可以使用条件结构或三元表达式创建嵌套条件。例如,此 if 结构在 condition1 与 condition2 或 condition3 成立时为 nestedCondition 变量赋值 true。然而,与上述逻辑表达式不同,该结构的分支还允许脚本在分配“布尔”值之前执行额外代码:
Mine Script®
已复制
无论哪种情况,在代码中处理复合或嵌套条件时,通过验证组成它们的单个条件的行为,可以避免许多麻烦并确保其按预期工作。
例如,此脚本计算 rsi 及其在 lengthInput 根K线上的中位数。然后,它创建五个变量来表示不同的单一条件。该脚本在逻辑表达式中使用这些变量为 compoundCondition 变量分配“布尔”值,并使用条件背景颜色显示 compoundCondition 的结果:

Mine Script®
已复制
如上所示,仅通过可视化最终结果来理解 compoundCondition 的行为并不一定容易,因为五个基础单一条件决定了最终值。在这种情况下要有效调试 compoundCondition,我们还必须检查组成它的各个条件。
在以下示例中,我们添加了五个 plotchar() 调用,以在每个单一条件出现时在图表上显示字符,并在状态行和数据窗口中显示数值。检查这些结果可以为我们提供关于 compoundCondition 行为的更完整信息:

Mine Script®
已复制
请注意:
- 每个 plotchar() 调用都使用条件数字作为序列参数。这些函数会在状态行和数据窗口中显示数值。
- 除
closeBelow条件的调用外,所有 plotchar() 调用均使用 location.absolute 作为位置参数,以便在其序列不为na(即条件成立时)在精确位置显示字符。closeBelow的调用使用 location.bottom 将其字符显示在窗格底部附近。
在本节示例中,我们将各个条件分配给具有直观名称和注释的独立变量。虽然创建复合条件并不强制要求这种格式(因为可以直接在逻辑表达式中组合条件),但如技巧部分所述,这种写法能生成更易读且便于调试的代码。
字符串
字符串是字母数字字符、控制字符及其他字符(如 Unicode)的序列。它们在调试脚本时非常实用,因为程序员可以用它们将脚本的数据类型表示为人类可读的文本,并通过具有文本相关属性的绘图类型或使用 Mine日志来检查这些文本。
表示其他类型
用户可以创建几乎任何数据类型的“字符串”表示形式,这在其他方法可能不足时有助于有效调试。在探索“字符串”检查技术之前,我们先简要回顾使用字符串表示脚本数据的方法。
Mine Script 包含预定义逻辑,可构建多种其他内置类型(如 int、float、bool、数组和矩阵)的“字符串”表示形式。脚本可以通过 str.tostring() 和 str.format() 函数方便地将此类类型表示为字符串。
例如,以下代码片段使用这些函数创建字符串来表示多个值:
Mine Script®
已复制
当处理象征 UNIX 时间戳的“整型”值时(例如由时间相关函数和变量返回的值),用户也可以使用 str.format() 或 str.format_time() 将其转换为人类可读的日期字符串。此代码块演示了使用这些函数转换时间戳的多种方法:
Mine Script®
已复制
当处理没有内置“字符串”表示形式的类型时(例如颜色、映射、用户定义类型等),程序员可以使用自定义逻辑或格式化来构建表示形式。例如,此代码调用 str.format() 来使用颜色的 r、g、b 和 t 分量表示“颜色”值:
Mine Script®
已复制
使用字符串表示数据的方法多种多样。在选择用于调试的字符串格式时,请确保结果具有可读性并能提供足够信息以供检查。以下部分将说明如何通过使用标签在图表上显示字符串来验证它们,而随后的章节将解释如何将字符串作为消息显示在 Mine日志面板中。
使用标签
标签允许脚本在图表上的任何可用位置显示动态文本(“序列字符串”)。在图表上显示此类文本的位置取决于程序员想要检查的信息及其调试偏好。
在连续K线上
当检查影响图表比例尺度的数值历史记录或处理具有不同类型的多个序列时,一种简单便捷的调试方法是在连续K线上绘制显示字符串表示的标签。
例如,此脚本计算四个序列:highestClose、percentRank、barsSinceHigh 和 isLow。它使用 str.format() 创建表示序列值和时间戳的格式化“字符串”,然后调用 label.new() 在每根K线的高点绘制显示结果的标签:

Mine Script®
已复制
虽然上述示例允许用户通过标签绘图检查任意K线上脚本序列的结果,但此类连续绘图会使图表显得杂乱,尤其是在查看较长字符串时。
另一种更视觉紧凑的检查连续K线数值的方法是使用 tooltip 属性而非 text 属性,因为标签仅在光标悬停时显示其工具提示。
在以下修改后的脚本中,我们将 label.new() 调用中的 text 参数替换为 debugString 作为 tooltip 参数。现在,我们可以在特定K线上查看结果,而不会产生额外视觉干扰:

Mine Script®
已复制
需要注意的是,一个脚本最多可显示 500 个标签绘图,这意味着上述示例仅允许用户检查最近 500 根图表K线的字符串。
如果程序员希望查看更早图表K线的结果,一种方法是创建条件逻辑,仅允许在特定时间范围内绘制标签,例如:
Mine Script®
已复制
如果我们在之前的示例中使用此结构,将 chart.left_visible_bar_time 和 chart.right_visible_bar_time 作为 startTime 和 endTime 值,脚本将仅在可见图表K线上创建标签,并避免在其他K线上绘制。通过此逻辑,只要可见范围内最多存在 max_labels_count 根K线,我们就可以滚动查看任意图表K线上的标签:

Mine Script®
已复制
请注意:
- 如果可见图表包含的K线数量超过允许的绘图数量,脚本将仅在可见范围内最新的K线上显示结果。使用此技术时,为获得最佳效果,请缩放图表以将可见范围限制在允许的绘图数量内。
在图表末端
使用标签调试脚本字符串的常用方法是在图表末端显示它们,即当字符串不发生变化或仅需分析特定K线的数值时。
以下脚本包含一个用户自定义的 printLabel() 函数,该函数会在图表的最后一个可用时间位置绘制标签,无论脚本何时调用它。在此示例中,我们使用该函数显示“Hello world!”字符串、一些基本图表信息以及数据源的当前 OHLCV 数值:

Mine Script®
已复制
请注意:
printLabel()函数使用 last_bar_time 和 chart.right_visible_bar_time 的最大值设置绘制标签的 x 坐标,以确保始终在最后一根可用K线显示结果。- 当从全局作用域调用时,该函数会创建一个带有
text和y属性的标签,这些属性会在每根K线上更新。 - 我们对该函数进行了三次调用并添加了换行符(
\n),以演示如果字符串具有足够的行间距,用户可以在图表末端叠加多个标签的结果。
使用表格
表格在相对于图表窗格视觉空间的固定位置,以列和行排列的单元格内显示字符串。它们可作为多功能的基于图表的调试工具,因为与标签不同,表格允许程序员以有组织的视觉结构检查一个或多个“序列字符串”,且不受图表比例或K线索引的影响。
例如,此脚本计算一个自定义过滤器,其结果为加权收盘价的指数移动平均(EMA)与权重序列的EMA之比。为了检查计算中使用的变量,它在第一根K线上创建表格实例,在最后一根历史K线上初始化表格单元格,然后在最新图表K线上使用 barsBack 根K线前的值的“字符串”表示更新必要的单元格:

Mine Script®
已复制
请注意:
- 脚本使用 var 关键字指定在第一根K线上分配给
debugTable变量的表格在整个脚本执行过程中持续存在。 - 此脚本在两个 if 结构内修改表格。第一个结构仅在最后确认的历史K线(barstate.islastconfirmedhistory)上使用 table.cell() 初始化单元格。第二个结构在最新可用K线(barstate.islast)上使用 table.cell_set_text() 调用,以变量的字符串表示更新相关单元格的
text属性。
需要重点注意的是,虽然表格可以提供调试实用性(特别是在处理多个序列或创建图表日志时),但相比本页讨论的其他技术,它们具有更高的计算成本且可能需要更多代码。此外,与标签不同,用户只能查看最新脚本执行时的表格状态。因此,我们建议在调试时明智且谨慎地使用表格,并尽可能选择简化方法。有关使用表格对象的更多信息,请参阅表格页面。
Mine日志
Mine 日志是脚本可在其执行特定点输出的交互式消息。它们为程序员提供了一种强大的方式来检查脚本的数据、条件和执行流程,且所需代码量极少。
与本页面讨论的其他工具不同,Mine 日志专为深入的脚本调试而设计。脚本不会在图表或数据窗口中显示 Mine 日志,而是会在专用的 Mine 日志面板中打印带时间戳的消息,该面板提供专门的导航功能和筛选选项。
要访问 Mine 日志面板,请从编辑器的“更多”菜单中选择“脚本日志”:

注意
只有个人脚本可以生成 Mine 日志。已发布的脚本无法创建日志,即使其代码中包含 log.*() 函数调用。在发布具有调试功能的脚本时,必须考虑替代方案,例如上文各节中概述的方法。
创建日志
脚本可通过调用 log.*() 命名空间中的函数来创建日志。
所有 log.*() 函数均具有以下签名:
log.*(message) → void
log.*(formatString, arg0, arg1, ...) → void第一个重载在 Mine 日志面板中记录指定消息。第二个重载类似于 str.format(),它会根据 formatString 和调用中提供的额外参数记录格式化消息。
每个 log.*() 函数具有不同的调试级别,允许程序员对面板中显示的结果进行分类和筛选:
log.info() 函数记录“信息”级别的条目,在面板中以灰色文本显示。 log.warning() 函数记录“警告”级别的条目,在面板中以橙色文本显示。 log.error() 函数记录“错误”级别的条目,在面板中以红色文本显示。
以下代码演示了所有三种 log.*() 函数之间的区别。它在第一根可用K线上调用 log.info()、log.warning() 和 log.error():

Mine Script®
已复制
Mine 日志可以在脚本执行的任何位置运行。它们允许程序员跟踪历史K线的信息,并监控脚本在实时未确认K线上的行为。在历史K线上执行时,脚本每根K线上每个 log.*() 调用会生成一次新消息。在实时K线上,对 log.*() 函数的调用可以在每个新跳动点上创建新条目。
例如,此脚本计算每根K线的收盘价-开盘价与其最高价-最低价范围的平均比率。当分母非零时,脚本调用 log.info() 在已确认K线上打印计算变量的值,并调用 log.warning() 在未确认K线上打印值。否则,它使用 log.error() 指示发生除零错误,因为此类情况会影响平均结果:

Mine Script®
已复制
请注意:
- Mine 日志不会在未确认K线的每个跳动点上回滚,这意味着这些跳动点的结果会一直显示在面板中,直到脚本重新开始执行。若仅需在已确认K线上记录消息,请在触发
log.*()调用的条件中使用 barstate.isconfirmed。 - 当在未确认K线上记录日志时,我们建议确保这些日志包含唯一信息或使用不同的调试级别,以便根据需要筛选结果。
- Mine 日志面板最多显示历史K线上最近的 10,000 条条目。如果脚本在历史K线上生成超过 10,000 条日志,且程序员需要查看更早的条目,可以使用条件逻辑将
log.*()调用限制在特定情况。有关将日志生成限制在用户指定时间范围的示例,请参阅本节内容。
检查日志
Mine 日志包含一些简化检查过程的有用功能。当脚本生成日志时,会自动在消息前添加精确时间戳以指示日志事件在时间序列中的发生位置。此外,每个条目都包含“源代码”和“滚动到K线”图标,这些图标在 Mine 日志面板中悬停时显示:

筛选日志
单个脚本可根据触发其 log.*() 调用的条件生成大量日志。当脚本仅生成少量日志时,直接滚动浏览日志历史记录查找特定条目可能足够,但在搜索数百或数千条消息时会变得难以管理。
Mine 日志面板包含多个用于筛选消息的选项,可通过隔离特定字符序列、开始时间和调试级别来简化结果。
点击面板顶部的“搜索”图标会打开搜索栏,可匹配文本以筛选已记录的消息。搜索筛选器还会以蓝色高亮显示每条消息中匹配的部分以供视觉参考。例如,此处我们输入“confirmed”以匹配先前脚本生成的所有包含该词的文本结果:

点击“开始日期”图标将打开一个对话框,允许用户指定结果中显示的第一条日志的日期和时间:

指定起始点后,包含开始时间的标签将出现在日志历史记录上方:

用户可通过选择筛选选项中最右侧图标时提供的复选框,按调试级别筛选结果。此处,我们已取消激活“信息”和“警告”级别,因此结果将仅包含“错误”消息:

使用输入
另一种更复杂的交互式筛选脚本日志结果的方法是创建与条件逻辑链接的输入,以激活代码中的特定 log.*() 调用。
让我们看一个示例。此代码计算收盘价的 RMA 并声明几个独特条件以形成复合条件。脚本使用 log.info() 在 Mine 日志面板中显示重要调试信息,包括 compoundCondition 变量及其结果所依赖的“布尔”变量的值。
我们声明了 filterLogsInput、logStartInput 和 logEndInput 变量,分别分配给 input.bool() 和两个 input.time() 调用,用于自定义日志筛选。当 filterLogsInput 为 true 时,脚本仅当K线时间介于 logStartInput 和 logEndInput 值之间时才会生成新日志,从而允许我们交互式隔离特定时间范围内发生的条目:

Mine Script®
已复制
请注意:
- 分配给
filterLogsInput、logStartInput和logEndInput变量的input.*()函数包含group参数,以便在脚本设置中对它们进行组织和区分。 - input.time() 调用包含
confirm = true,以便我们可以直接在图表上交互式设置开始和结束时间。要重置输入,请从脚本“更多”菜单的选项中选择“重置点…”。 - 触发每个 log.info() 调用的条件包含 barstate.isconfirmed,以将日志生成限制在已确认的K线。
调试函数
用户定义函数和方法是由用户编写的自定义函数。它们封装了脚本可在后续执行中调用的操作序列。
每个用户定义函数或方法都有一个嵌入脚本全局作用域的局部作用域。函数签名中的参数和函数体内声明的变量属于该函数的局部作用域,脚本的外部作用域或其他函数的作用域无法直接访问它们。
以下部分将解释程序员调试函数局部作用域值的几种方法。我们将使用此脚本作为后续示例的起点。它包含一个 customMA() 函数,该函数返回一个指数移动平均,其平滑参数根据源数据在 length 根K线上 25% 和 75% 分位数之外的距离而变化:

Mine Script®
已复制
提取局部变量
当程序员希望通过绘制数值、设置背景或图表K线颜色等方式检查用户定义函数的局部变量时,必须将这些值提取到全局作用域,因为生成此类输出的内置函数只能接受全局变量和字面量。
由于函数返回的值在调用发生的作用域中可用,一种直接的提取方法是让函数返回一个包含所有需要检查值的元组。
此处,我们修改了 customMA() 函数以返回包含函数所有计算变量的元组。现在,我们可以通过元组声明调用函数,使这些值在全局作用域中可用,并通过绘图进行检查:

Mine Script®
已复制
请注意:
- 我们使用
display.all - display.pane作为outerRangeDebug、totalRangeDebug和alphaDebug变量的绘图设置,以避免影响图表比例尺。 - 脚本还使用条件颜色在高亮图表窗格背景当
debugAlpha为0时,表明maValue未发生变化。
另一种更高级的提取函数局部变量值的方法是将其传递给在全局作用域中声明的引用类型变量。
函数作用域可以访问全局变量进行计算。虽然脚本无法直接从函数作用域内重新分配全局变量的值,但如果这些值是引用类型(如数组、矩阵、映射和用户定义类型),则可以更新这些值的元素或属性。
此版本在全局作用域声明了一个 debugData 变量,该变量引用具有“字符串”键和“浮点”值的映射。在 customMA() 函数的局部作用域内,脚本将包含每个局部变量名称和值的键值对放入映射中。调用函数后,脚本绘制存储的 debugData 值:
Mine Script®
已复制
请注意:
- 我们将每个 map.put() 调用与变量声明放在同一行,并用逗号分隔,以保持简洁并避免向
customMA()代码添加额外行。 - 我们使用 map.get() 为调试 plot() 和 bgcolor() 调用检索每个值。
局部绘图与日志
与 plot.*() 函数及其他需要全局作用域可访问值的函数不同,脚本可以直接在函数内部生成绘图对象和 Mine日志,从而使程序员能够灵活调试其局部变量,而无需将值提取到外部作用域。
在此示例中,我们使用标签和 Mine日志来显示 customMA() 作用域内值的字符串表示。在函数内部,脚本调用 str.format() 创建表示局部作用域数据的格式化字符串,随后调用 label.new() 和 log.info(),分别在图表的工具提示中显示文本并在 Mine 日志面板中记录包含该文本的“信息”消息:

Mine Script®
已复制
请注意:
- 我们在 indicator() 函数中包含
max_labels_count = 500,以显示最近500次customMA()调用的标签。 - 该函数在 if 语句中使用 barstate.isconfirmed,仅对已确认的K线调用 log.info()。它不会在每个实时跳动点上记录新消息。
调试循环
循环是基于计数器(for)、集合内容(for…in)或条件(while)重复执行代码块的结构。它们允许脚本执行重复性任务而无需冗余代码行。
每个循环实例维护一个独立的局部作用域,所有外部作用域均无法访问该作用域。在循环作用域内声明的所有变量仅适用于该循环,意味着无法在外部作用域中使用它们。
与 Mine 中的其他结构一样,调试循环有多种可能方法。本节探讨一些实用技术,包括提取局部值用于绘图、使用绘图检查值以及通过 Mine日志跟踪循环执行。
我们将以此脚本作为后续示例的起点。该脚本聚合 close 值在 1 - lookbackInput 根K线上的变化率,并在 for 循环中累加它们,然后将结果除以 lookbackInput 以计算最终平均值:

Mine Script®
已复制
请注意:
aroc是在循环内修改的全局变量,而pastClose和roc是外部作用域无法访问的局部变量。
检查单个迭代
当程序员需要专注于特定循环迭代时,可以使用多种技术,其中大多数技术涉及在循环内部使用条件来触发调试操作,例如将值提取到外部变量、创建绘图、记录日志消息等。
此示例通过三种不同方式检查循环中单个迭代的局部 roc 值。当循环计数器的值等于 debugCounterInput 时,脚本将 roc 赋值给全局作用域中的 rocDebug 变量用于绘图,使用 line.new() 从 0 到 roc 值绘制垂直线,并使用 log.info() 在 Mine日志面板中记录消息:

Mine Script®
已复制
请注意:
- 分配给
debugCounterInput的 input.int() 调用包含group参数,以在脚本设置中区分它。 - 当 barstate.isconfirmed 为 true 时,log.info() 调用在格式化消息中包含“(已确认)”。在 Mine日志面板中搜索此文本将筛选出来自未确认K线的条目。请参阅上文筛选日志部分。
检查多个迭代
当检查多个循环迭代的值时,通常有助于使用集合或字符串来收集结果,以便在循环终止后用于输出函数。
此版本演示了几种收集和显示所有迭代循环值的方法。它在全局作用域中声明了一个 logText 字符串和一个 debugValues 数组。在 for 循环的局部作用域内,脚本将 length 和 roc 的字符串表示与 logText 连接,并调用 array.push() 将迭代的 roc 值推入 debugValues 数组。
循环结束后,脚本绘制 debugValues 数组的第一个和最后一个值,绘制一个标签并在工具提示中显示数组的字符串表示,并在K线确认时在 Mine日志面板中显示 logText:

Mine Script®
已复制
另一种检查多个迭代循环的方法是在循环作用域内生成顺序 Mine日志或创建/修改绘图对象,以精细跟踪其执行模式。
此示例使用 Mine日志来跟踪脚本循环的执行流程。它在每次迭代时生成新的“信息”消息,以在每根确认K线上循环进行时跟踪局部作用域的计算:

Mine Script®
已复制
请注意:
- 当从循环内部迭代生成日志或绘图时,务必避免不必要的杂乱并力求易于导航。对于调试而言,并非越多越好,尤其是在循环内工作时。
技巧
组织性与可读性
编写脚本时,优先考虑组织有序、可读性强的源代码是明智之举。结构清晰且易于阅读的代码有助于简化调试过程。此外,精心编写的代码更易于长期维护。
以下基于我们的风格指南和本页示例提供一些简要建议:
- 力求遵循通用脚本组织规范。使用此结构组织脚本可使内容更易于定位和检查。
- 选择易于识别和理解的变量及函数名称。命名约定部分提供了一些示例。
- 在调试过程中,将表达式的重要部分临时分配给具有描述性名称的变量通常很有帮助。将表达式分解为可重复使用的部分有助于简化检查流程。
- 使用注释和标注(
//@function、//@variable等)为代码添加文档。标注尤其有用,因为 Mine 编辑器的自动建议功能会在代码中任何位置悬停标识符时在弹出窗口中显示变量和函数描述。 - 请记住,在许多情况下“少即是多”。调试时不要用过多的脚本输出或不必要的信息使自己不堪重负。保持简洁,仅包含所需的信息量。
加速重复性任务
在调试代码时,我们经常使用一些便捷技巧:
使用 plotchar() 或 plotshape() 在脚本状态行和数据窗口中快速显示“整型”、“浮点型”或“布尔型”变量及表达式的结果。 常用 bgcolor() 在图表上可视化特定条件的历史情况。 使用本节中单行版本的 printLabel() 函数在图表末端打印字符串。 使用带 tooltip 参数的 label.new() 调用在连续K线的工具提示中显示字符串。 使用 log.*() 函数在 Mine日志面板中快速显示字符串形式的数据。
当建立常规调试流程后,创建键盘宏通常有助于加速重复性任务,并减少在每个代码中设置调试输出的时间。
以下是一个简单的 AutoHotkey 脚本(非 Mine 脚本代码),包含针对上述五种技术的热字符串。该脚本通过输入特定字符序列后跟空格来生成代码片段:
; ————— This is AHK code, not Mine Script. —————
; Specify that hotstrings trigger when they end with space, tab, linefeed, or carriage return.
#Hotstring EndChars `t `n `r
:X:,,show::SendInput, plotchar(%Clipboard%, "%Clipboard%", "", color = chart.fg_color, display = display.all - display.pane){Enter}
:X:,,highlight::SendInput, bgcolor(bool(%Clipboard%) ? color.new(color.orange, 80) : na, title = "%Clipboard% highlight"){Enter}
:X:,,print::SendInput, printLabel(string txt, float price = na) => int labelTime = math.max(last_bar_time, chart.right_visible_bar_time), var label result = label.new(labelTime, na, txt, xloc.bar_time, na(price) ? yloc.abovebar : yloc.price, na, label.style_none, chart.fg_color, size.large), label.set_text(result, txt), label.set_y(result, price), result`nprintLabel(){Left}
:X:,,tooltip::SendInput, label.new(bar_index, high, color = color.new(chart.fg_color, 70), tooltip = str.tostring(%Clipboard%)){Enter}
:X:,,log::SendInput, log.info(str.tostring(%Clipboard%)){Enter}“,,show”宏生成一个plotchar()调用,该调用使用剪贴板内容作为序列和标题参数。复制variableName变量或close > open表达式并键入“,,show”后跟空格将分别产生:
Mine Script®
已复制
“,,highlight”宏生成一个bgcolor()调用,该调用根据复制到剪贴板的变量或表达式,使用条件颜色突出显示图表窗格的背景。例如,复制barstate.isrealtime变量并键入“,,highlight”后跟空格将产生:
Mine Script®
已复制
“,,print”宏生成单行printLabel()函数并创建一个空的printLabel()调用,同时将光标置于其内部。键入“,,print”后跟空格后,您只需输入要显示的文本:
Mine Script®
已复制
“,,tooltip”宏生成一个带有tooltip参数的label.new()调用,该参数对剪贴板内容使用str.tostring()函数。复制variableName变量并键入“,,tooltip”后跟空格将产生:
Mine Script®
已复制
“,,log”宏生成一个带有message参数的log.info()调用,该参数对剪贴板内容使用str.tostring()函数,以在Mine日志面板中显示变量和表达式的字符串表示形式。复制表达式bar_index % 2 == 0并键入“,,log”后跟空格将产生:
Mine Script®
已复制
请注意:
- AHK适用于Windows设备。如果您的机器使用其他操作系统,请研究其他软件以实现类似流程。