先进的

枚举

介绍

Pine Script™ 枚举,也称为枚举枚举类型枚举类型,是一种独特的数据类型,其所有可能的值(成员)均由程序员明确定义。它们提供了一种人性化、富有表现力的方式来声明变量、条件表达式和 集合可以接受的不同预定义值集,从而可以更严格地控​​制脚本逻辑中使用的值。

声明枚举

要声明枚举,请使用 enum 关键字,语法如下:

[export ]enum <enumName>
<field_1>[ = <title_1>]
<field_2>[ = <title_2>]
...
<field_N>[ = <title_N>]

枚举中的每个字段都代表枚举类型的唯一命名成员(值)。用户可以为枚举字段指定可选的“常量字符串”标题,以添加有关其值所代表内容的额外信息。如果程序员未指定字段的标题,则其标题是其名称的“字符串”表示形式。 枚举输入在脚本的“设置/输入”选项卡的下拉菜单中显示枚举字段标题。脚本还可以使用 str.tostring () 函数检索枚举字段标题,从而允许将其用于其他计算。 有关更多信息,请参阅下面的部分。

虽然上述语法看起来类似于声明 用户定义类型 (UDT)的语法,但了解 枚举类型UDT 的用途不同至关重要。脚本使用 UDT 创建具有“系列”字段的对象,这些字段可以保存任何指定类型的值。相比之下,枚举是不同的“简单”字段组,表示变量、表达式和 集合可以接受的相同唯一类型的特定预定义值

例如,此代码块声明了一个Signal具有三个字段的枚举: buysell和。每个字段代表枚举类型neutral的一个不同成员(可能的值)Signal

//@enum           An enumeration of named values representing buy, sell, and neutral signal states.
//@field buy      Represents a "Buy signal" state.
//@field sell     Represents a "Sell signal" state.
//@field neutral  Represents a "neutral" state. 
enum Signal
    buy     = "Buy signal"
    sell    = "Sell signal"
    neutral 

注意:

  • 标识符Signal代表枚举的名称,表明字段所属的唯一类型。
  • 我们使用//@enum//@field 注释来记录枚举及其字段的含义。
  • buy与和字段不同sellneutral字段不包含指定标题。因此,其标题是其名称的“字符串”表示(“中性”)。

要检索枚举的成员,请使用点符号语法引用其字段名称,即:

enumName.fieldName

与其他类型一样,脚本可以将枚举成员分配给变量、函数参数和 UDT 字段,从而严格控制它们的允许值。

例如,以下代码行声明了一个mySignal变量,其值是枚举neutral的成员Signal。 稍后分配给此变量的任何值也必须是相同的 枚举类型

mySignal = Signal.neutral

请注意,上面这一行不需要将变量的 类型声明为,Signal因为编译器可以根据赋值自动推断出该信息。如果我们改用 na作为初始值,则必须使用Signaltype 关键字来指定mySignal将接受Signal成员:

Signal mySignal = na

使用枚举

脚本可以使用==!=运算符比较枚举成员 ,并在条件结构 中使用它们 ,从而可以方便地创建逻辑模式,同时降低出现意外值或操作的风险。

以下示例声明了一个OscType枚举,其中三个字段代表不同的振荡器选择:rsimficci。该 calcOscillator()函数使用switchOscType结构中的成员 来确定要计算哪个振荡器。脚本使用枚举输入 中的值 作为函数的参数来调用此函数,并绘制生成的振荡器:selection

图像

//@version=5
indicator("Using enums demo")

//@enum An enumeration of oscillator choices.
enum OscType
    rsi = "Relative Strength Index"
    mfi = "Money Flow Index"
    cci = "Commodity Channel Index"

//@variable An enumerator (member) of the `OscType` enum.
OscType oscInput = input.enum(OscType.rsi, "Oscillator type")

//@function         Calculates one of three oscillators based on a specified `selection`.
//@param source     The series of values to process.
//@param length     The number of bars in the calculation.
//@param selection  Determines which oscillator to calculate.
calcOscillator(float source, simple int length, OscType selection) =>
    result = switch selection
        OscType.rsi => ta.rsi(source, length)
        OscType.mfi => ta.mfi(source, length)
        OscType.cci => ta.cci(source, length)

// Plot the value of a `calcOscillator()` call with `oscInput` as the `selection`.
plot(calcOscillator(close, 20, oscInput))

注意:

  • selection该函数的参数只能calcOscillator()四个值之一:OscType.rsiOscType.mfiOscType.ccina
  • 脚本“设置/输入”选项卡中的“振荡器类型”输入OscType在其下拉列表中显示所有字段标题。请参阅 本节以了解有关枚举输入的更多信息。

需要注意的是,每个声明的枚举都代表一个唯一的 类型。脚本无法比较不同枚举的成员,也无法在需要特定 枚举类型的表达式中使用此类成员,即使字段具有相同的名称和标题。

在此示例中,我们OscType2向上述脚本添加了一个枚举,并将oscInput变量更改为使用该枚举的成员。该脚本现在引发编译错误,因为它无法使用枚举的成员 OscType2作为selection调用中的参数calcOscillator()

//@version=5
indicator("Incompatible enums demo")

//@enum An enumeration of oscillator choices.
enum OscType
    rsi = "Relative Strength Index"
    mfi = "Money Flow Index"
    cci = "Commodity Channel Index"

//@enum An enumeration of oscillator choices. Its fields DO NOT represent the same values those in the `OscType` enum.
enum OscType2
    rsi = "Relative Strength Index"
    mfi = "Money Flow Index"
    cci = "Commodity Channel Index"

//@variable An enumerator (member) of the `OscType2` enum.
OscType2 oscInput = input.enum(OscType2.rsi, "Oscillator type")

//@function         Calculates one of three oscillators based on a specified `selection`.
//@param source     The series of values to process.
//@param length     The number of bars in the calculation.
//@param selection  Determines which oscillator to calculate.
calcOscillator(float source, simple int length, OscType selection) =>
    result = switch selection
        OscType.rsi => ta.rsi(source, length)
        OscType.mfi => ta.mfi(source, length)
        OscType.cci => ta.cci(source, length)

// Plot the value of a `calcOscillator()` call with `oscInput` as the `selection`.
// Raises a compilation error because only members of `OscType` are allowed. 
plot(calcOscillator(close, 20, oscInput))

利用字段标题

枚举字段的“字符串”标题允许程序员为每个成员添加额外信息。调用 input.enum() 函数时,这些字段标题会显示在脚本“设置/输入”选项卡的下拉选项卡中。

脚本还可以在计算和逻辑中使用枚举字段标题。对枚举字段使用字符串转换函数 ( str.tostring() ) 来访问其标题。

以下示例组合了不同的枚举字段标题,以构造股票代码 ID,用于从 另一个上下文请求数据。该脚本声明了两个枚举,ExchangePair,其各自的字段代表交易所货币对名称。它使用 input.enum() 将用户指定的枚举成员分配给exchangeInput和 变量,然后使用str.tostring()pairInput从这些变量中检索“字符串”标题 ,并将它们连接起来形成“Exchange:Symbol”对,以用于 request.security () 调用:

图像

//@version=5
indicator("Utilizing field titles demo")

//@enum An enumeration of cryptocurrency exchanges. All field titles are the same as the field names.
enum Exchange
    BINANCE
    BITSTAMP
    BITFINEX
    COINBASE
    KRAKEN

//@enum An enumeration of cryptocurrency pairs. All the field titles are the same as the field names. 
enum Pair
    BTCUSD
    ETHUSD
    SOLUSD
    XRPUSD

//@variable An enumerator (member) of the `Exchange` enum.
Exchange exchangeInput = input.enum(Exchange.BINANCE, "Exchange")
//@variable An enumerator (member) of the `Pair` enum.
Pair pairInput = input.enum(Pair.BTCUSD, "Pair")

//@variable The exchange-symbol pair for the data request. 
simple string symbol = str.tostring(exchangeInput) + ":" + str.tostring(pairInput)

// Plot the `close` value requested from the `symbol` context.
plot(request.security(symbol, timeframe.period, close), "Requested close", color.purple, 3)

注意:

  • Exchange或枚举的成员均未Pair指定标题。因此,每个字段的标题都是其名称的“字符串”表示,如脚本的 枚举输入所示。
  • 对枚举字段调用 str.tostring()函数是检索其标题以进行其他计算的 唯一方法。str.format ()log.*()函数不能接受枚举成员。要在字符串格式化函数中使用字段的标题,请先对字段调用 str.tostring() ,然后将生成的“字符串”传递给函数。

收集枚举成员

Pine Script™ 集合矩阵映射可以存储枚举成员,从而严格控制它们可以包含的值。要声明枚举成员的集合,请在集合的 类型模板中包含枚举的名称

例如,此代码块创建一个空 数组 来保存枚举成员FooBar。此数组可以允许作为元素的唯一值是FooBar.fooFooBar.barFooBar.bazna

//@variable An enumeration of miscellaneous named members.
enum FooBar
    foo
    bar
    baz

//@variable An array that can only contain the following values: `FooBar.foo`, `FooBar.bar`, `FooBar.baz`, `na`.
array<FooBar> fooBarArray = array.new<FooBar>()

枚举在使用映射时特别有用 ,因为与其他非基本 类型不同 ,脚本可以使用枚举类型键声明映射,从而能够严格控制其键值对中允许的所有可能的键。

以下示例使用 带有枚举键和“int”值的映射 来跟踪和计数图表条中的信号状态。脚本的Signal枚举包含五个字段,代表特定的命名状态。signalCounters 映射 使用Signal名称作为类型模板中的第一个关键字来指定它只能接受成员作为键。Signal

该脚本使用 switch 结构来计算一个signalState变量,该变量的值是枚举的成员Signal,它使用该变量来确定要在映射中更新的计数器值。它构造一个“字符串”来表示映射signalCounters的键值对 ,并在 最后一个图表栏上的 单个单元格 表中显示结果:

图像

//@version=5
indicator("Collecting enum members demo", overlay = true)

//@enum An enumeration of named signal states. 
enum Signal
    strongBuy  = "Strong buy"
    buy        = "Buy"
    neutral    = "Neutral"
    sell       = "Sell"
    strongSell = "Strong sell"

//@variable The number of bars in the signal calculation.
int lengthInput = input.int(50, "Length", 2)

//@variable A map of `Signal.*` keys and "int" values counting the number of bars with each signal state. 
//          Allowed keys: `Signal.strongBuy`, `Signal.buy`, `Signal.neutral`, `Signal.sell`, `Signal.strongSell`, `na`.
var map<Signal, float> signalCounters = map.new<Signal, float>()

//@variable A single-cell table displaying the key-value pairs of the `signalCounters` map.
var table infoTable = table.new(position.top_right, 1, 1, chart.fg_color)

if barstate.isfirst
    // Put `Signal.*`-"int" pairs into the `signalCounters` map to establish insertion order.
    signalCounters.put(Signal.strongBuy, 0)
    signalCounters.put(Signal.buy, 0)
    signalCounters.put(Signal.neutral, 0)
    signalCounters.put(Signal.sell, 0)
    signalCounters.put(Signal.strongSell, 0)
    // Initialize the `infoTable` cell.
    infoTable.cell(0, 0, text_color = chart.bg_color, text_halign = text.align_left, text_size = size.large)

// Calculate the EMA and Percent rank of `source` data over `length` bars.
float ema  = ta.ema(close, lengthInput)
float rank = ta.percentrank(close, lengthInput)

//@variable A `Signal` member representing the current signal state based on `ema` and `rank` values. 
Signal signalState = switch
    close > ema => rank > 70 ? Signal.strongBuy  : rank > 50 ? Signal.buy  : Signal.neutral
    close < ema => rank < 30 ? Signal.strongSell : rank < 50 ? Signal.sell : Signal.neutral
    => Signal.neutral

// Add 1 to the value in the `signalCounters` map associated with the `signalState` key.
signalCounters.put(signalState, signalCounters.get(signalState) + 1)

// Update the `infoTable` cell's text using the keys and values from the `signalCounters` map on the last bar.
if barstate.islast
    string tableText = ""
    for [state, count] in signalCounters
        tableText += str.tostring(state) + ": " + str.tostring(count) + "\n"
    infoTable.cell_set_text(0, 0, str.trim(tableText))

注意:

  • signalCounters映射最多可包含六个键值对,因为Signal枚举具有五个预定义值,加上可能的值 na,并且映射不能包含重复的键。
  • 该脚本signalCounters使用 var 关键字声明变量,表示分配的 映射 实例在执行过程中持续存在。
  • 在第一个图表栏上,脚本使用了五个 map.put() 调用来建立地图中键的 插入顺序signalCounters有关更多信息,请参阅地图页面的此部分。
  • 为了最大限度地减少资源使用,脚本 在第一个柱状图infoTable上声明并初始化其单元格,然后在最新的柱状图上更新单元格的文本。请参阅 分析和优化页面的 此部分以了解更多信息。

阴影

为了避免将来添加到 Pine Script™ 的命名空间与现有脚本中的枚举名称发生冲突的潜在冲突,枚举名称可以遮蔽一些 Pine 的命名空间。

例如,可以声明如下所示的枚举,其名称覆盖syminfo.*命名空间:

//@version=5
indicator("Shadowing demo")

enum syminfo
    abcd

log.info(str.tostring(syminfo.abcd))

但是,仅当枚举的字段没有与命名空间的任何内置项匹配的名称时,才允许对枚举使用这样的名称。否则,Pine 将无法确定脚本应该使用哪个值,从而导致编译错误:

//@version=5
indicator("Name conflict demo")

enum syminfo
    abcd
    tickerid // This matches the built-in `syminfo.tickerid` variable, causing a compilation error.

log.info(str.tostring(syminfo.tickerid))

此外,不能使用任何 Pine 的内置 类型名称作为枚举的名称。

Original text
Rate this translation
Your feedback will be used to help improve Google Translate