omo o valor histórico na barra anterior de close, b também é uma estrutura de sequência de tempo, que pode continuar a referir-se ao seu valor histórico.
Podemos puxar o gráfico para o lado esquerdo e observar que na primeira linha K, os valores de b e c são nulos ((na)). Isso ocorre porque, quando o script é executado na primeira linha K BAR, quando o histórico de referência de um ou dois períodos para a frente é nulo, ele não existe. Por isso, quando escrevemos uma estratégia, precisamos ter cuidado para não citar o valor nulo quando citamos dados históricos. Se não formos cuidadosos, o uso do valor nulo pode causar uma série de diferenças de cálculo e até mesmo afetar o tempo real.na
、nz
A função embutida é a função que julga a função embutida, e a função embutida julga a função embutida.nz
、na
Funções, lembra-se em que capítulo?) que tratam especificamente de valores vazios, como:
close > nz(close[1], open) // 当引用close内置变量前一个BAR的历史值时,如果不存在,则使用open内置变量
Isso é um tratamento para o que pode ser citado como um valor nulo ((na)).
Nós já aprendemos muitos operadores da linguagem Pine, que formam expressões através de várias combinações de números e operações. Então, como é a prioridade dessas operações quando se calcula em expressões? Como as operações de quatro regras que aprendemos quando fomos para a escola, há multiplicação e subtração com prioridade e adição e subtração.
Prioridade | Operador |
---|---|
9 | [] |
8 | O operador da base de dados + 、- e `not |
7 | * 、/ 、% |
6 | O operador binário + , - |
5 | > 、< 、>= 、<= |
4 | == 、!= |
3 | and |
2 | or |
1 | ?: |
A parte da expressão com alta prioridade é operada primeiro, e se a mesma prioridade é operada da esquerda para a direita. Se você quiser forçar uma parte a ser operada primeiro, pode usar()
Envolva a parte da expressão que é obrigatória para a operação.
Nós já aprendemos o conceito de um identificador de variável, o identificador de variável é o nome dado a uma variável como um nome de variável. Então, também podemos dizer que uma variável é um identificador de um valor preservado. Então, como declarar uma variável?
var
。
2o, usar palavras-chave.varip
。
var
、varip
A palavra-chave já foi aprendida no capítulo anterior “Operadores de atribuição” e não é mais mencionada aqui. Se o padrão de declaração da variável não escrever nada, por exemplo, a frase:i = 1
Na verdade, como dissemos anteriormente, as variáveis declaradas e atribuídas são executadas em cada linha BAR de K.
int i = 0
float f = 1.1
Os tipos no Trading View são mais exigentes, e o uso do seguinte código no Trading View pode gerar erros:
baseLine0 = na // compile time error!
Em resumo, a declaração de uma variável pode ser escrita como:
// [<declaration_mode>] [<type>] <identifier> = value
声明模式 类型 标识符 = 值
O operador de atribuição é usado aqui:=
A atribuição de valores às variáveis pode ser uma string, um valor, uma expressão, uma chamada de função, ou um número.if
、 for
、while
ouswitch
Estrutura etc. ((Essas palavras-chave estruturais, o uso de frases serão explicados em detalhes em nossos cursos posteriores, na verdade, nós já aprendemos em um curso anterior a atribuição de uma simples frase if, pode rever)
A função de entrada é uma função que usamos com muita frequência na elaboração de estratégias.
Funções de entrada:
input函数,参数defval、title、tooltip、inline、group
A função de entrada no FMZ é um pouco diferente da função de entrada no Trading View, mas é usada como uma entrada de atribuição de um parâmetro de estratégia. A seguir, vamos detalhar o uso da função de entrada no FMZ com um exemplo:
param1 = input(10, title="参数1名称", tooltip="参数1的描述信息", group="分组名称A")
param2 = input("close", title="参数2名称", tooltip="参数2的描述信息", group="分组名称A")
param3 = input(color.red, title="参数3名称", tooltip="参数3的描述信息", group="分组名称B")
param4 = input(close, title="参数4名称", tooltip="参数4的描述信息", group="分组名称B")
param5 = input(true, title="参数5名称", tooltip="参数5的描述信息", group="分组名称C")
ma = ta.ema(param4, param1)
plot(ma, title=param2, color=param3, overlay=param5)
A atribuição de valores às variáveis durante a declaração de variáveis é frequentemente usada como uma função de entrada, na qual a função de entrada do FMZ desenha automaticamente no interface da política do FMZ um controle para a configuração de parâmetros de política. Os controles suportados no FMZ atualmente possuem caixa de entrada de valores, caixa de entrada de texto, caixa de deslize e seleção de valores de burro. Também é possível configurar o grupo de parâmetros de política e informações de texto de aviso para a configuração de parâmetros.
Aqui estão alguns dos principais parâmetros da função de entrada:
Além de uma declaração de variável individual, a linguagem Pine também declara um conjunto de variáveis e atribui um valor:
[变量A,变量B,变量C] = 函数 或者 ```if```、 ```for```、```while```或```switch```等结构
O mais comum é o que usamosta.macd
Quando a função calcula o MACD, como o MACD é um indicador de várias linhas, calcula três conjuntos de dados. Portanto, pode ser escrito como:
[dif,dea,column] = ta.macd(close, 12, 26, 9)
plot(dif, title="dif")
plot(dea, title="dea")
plot(column, title="column", style=plot.style_histogram)
É muito fácil de desenhar um gráfico MACD usando o código acima. Não só as funções embutidas podem retornar várias variáveis, mas também as funções personalizadas podem retornar vários dados.
twoEMA(data, fastPeriod, slowPeriod) =>
fast = ta.ema(data, fastPeriod)
slow = ta.ema(data, slowPeriod)
[fast, slow]
[ema10, ema20] = twoEMA(close, 10, 20)
plot(ema10, title="ema10", overlay=true)
plot(ema20, title="ema20", overlay=true)
O uso de estruturas como if como atribuição de valores a várias variáveis também é semelhante ao método de função personalizada acima, e os interessados também podem tentar.
[ema10, ema20] = if true
fast = ta.ema(close, 10)
slow = ta.ema(close, 20)
[fast, slow]
plot(ema10, title="ema10", color=color.fuchsia, overlay=true)
plot(ema20, title="ema20", color=color.aqua, overlay=true)
Algumas funções não podem ser escritas em blocos de código local de ramificações condicionais, principalmente as seguintes:
barcolor(), fill(), hline(), indicator(), plot(), plotcandle(), plotchar(), plotshape()
O Trading View compila relatórios de erros. As restrições do FMZ não são tão rigorosas, mas também é recomendado seguir as normas do Trading View. Por exemplo, embora não haja relatórios de erros no FMZ, não é recomendado escrever assim.
strategy("test", overlay=true)
if close > open
plot(close, title="close")
else
plot(open, title="open")
Exemplo:
var lineColor = na
n = if bar_index > 10 and bar_index <= 20
lineColor := color.green
else if bar_index > 20 and bar_index <= 30
lineColor := color.blue
else if bar_index > 30 and bar_index <= 40
lineColor := color.orange
else if bar_index > 40
lineColor := color.black
else
lineColor := color.red
plot(close, title="close", color=n, linewidth=5, overlay=true)
plotchar(true, title="bar_index", char=str.tostring(bar_index), location=location.abovebar, color=color.red, overlay=true)
Nota: A expressão usada para julgar retorna um valor de burr. Note que não há mais do que uma subalterna else. Todas as subalternas expressões são falsas, e sem nenhuma subalterna else, retorna na.
x = if close > open
close
plot(x, title="x")
Como o bloco local de if não é executado quando a linha K BAR é negativa, ou seja, quando close < open, a expressão após a frase if é falsa, não há nenhuma ramificação else, a frase if retorna na. x é atribuído a na. Este ponto não pode ser desenhado no diagrama, mas também pode ser observado pelo diagrama de ressonância.
A sentença de switch também é uma sentença de estrutura ramificada, usada para projetar diferentes caminhos de execução de acordo com certas condições. A sentença de switch geralmente tem os seguintes pontos-chave de conhecimento:
1 , a sentença switch, tal como a sentença if, também pode retornar um valor. 2. Ao contrário das declarações de switch em outras linguagens, quando a estrutura de switch é executada, apenas um bloco local de seu código é executado, então a declaração de quebra não é necessária (ou seja, não é necessário escrever palavras-chave como break). 3. cada uma das sucursais do switch pode escrever um bloco de código local, cuja última linha é o valor de retorno (que pode ser um subconjunto de um valor). Se nenhum dos blocos de código local dos quais as sucursais são executadas, o retorno é na. 4 , a posição de julgamento de expressões na estrutura do switch, pode escrever strings, variáveis, expressões ou chamadas de funções. 5. switch permite especificar um valor de retorno, que é o valor padrão usado quando não há outra situação na estrutura.
O switch é dividido em duas formas, vamos ver um exemplo e ver como ele é usado.
1 com expressãoswitch
A história é contada por exemplo:
// input.string: defval, title, options, tooltip
func = input.string("EMA", title="指标名称", tooltip="选择要使用的指标函数名称", options=["EMA", "SMA", "RMA", "WMA"])
// input.int: defval, title, options, tooltip
// param1 = input.int(10, title="周期参数")
fastPeriod = input.int(10, title="快线周期参数", options=[5, 10, 20])
slowPeriod = input.int(20, title="慢线周期参数", options=[20, 25, 30])
data = input(close, title="数据", tooltip="选择使用收盘价、开盘价、最高价...")
fastColor = color.red
slowColor = color.red
[fast, slow] = switch func
"EMA" =>
fastLine = ta.ema(data, fastPeriod)
slowLine = ta.ema(data, slowPeriod)
fastColor := color.red
slowColor := color.red
[fastLine, slowLine]
"SMA" =>
fastLine = ta.sma(data, fastPeriod)
slowLine = ta.sma(data, slowPeriod)
fastColor := color.green
slowColor := color.green
[fastLine, slowLine]
"RMA" =>
fastLine = ta.rma(data, fastPeriod)
slowLine = ta.rma(data, slowPeriod)
fastColor := color.blue
slowColor := color.blue
[fastLine, slowLine]
=>
runtime.error("error")
plot(fast, title="fast" + fastPeriod, color=fastColor, overlay=true)
plot(slow, title="slow" + slowPeriod, color=slowColor, overlay=true)
Antes de começarmos a estudar as funções de input, vamos continuar a estudar duas funções semelhantes a input:input.string
、input.int
função.
input.string
O que é o código de barras?input.int
Função usada para retornar um valor inteiro.options
O uso de parâmetros,options
Os parâmetros podem ser passados para um conjunto de valores selecionáveis.options=["EMA", "SMA", "RMA", "WMA"]
eoptions=[5, 10, 20]
(Observe que um deles é de tipo string e o outro é de tipo numérico). Assim, os controles da interface de estratégia não precisam inserir valores específicos, mas os controles se transformam em caixas de seleção para selecionar as opções fornecidas no parâmetro options.
O valor da variável func é uma sequência de caracteres, a variável func como uma expressão do switch, que pode ser uma variável, uma chamada de função, uma expressão, para determinar qual ramo do switch será executado. Se a variável func não for capaz de corresponder a uma expressão em qualquer ramo do switch, a execução do bloco de código do ramo padrão será executada.runtime.error("error")
A função faz com que a política de lançamento de exceções pare.
No nosso código de teste acima, depois da última linha de runtime.error do bloco de código de suporte padrão do switch, não adicionamos[Na, na] como um código para compatibilizar o valor de retorno, no trading view é necessário considerar o problema, se o tipo não é consistente será compensado. Mas na FMZ, como não há tipo de exigência rigorosa, pode ser omitido este código de compatibilidade. Portanto, na FMZ não precisa considerar o tipo de compatibilidade do valor de retorno do ramo if, switch.
strategy("test", overlay=true)
x = if close > open
close
else
"open"
plotchar(true, title="x", char=str.tostring(x), location=location.abovebar, color=color.red)
No FMZ, não há erros, mas no trading view há erros. Porque o tipo de retorno de if branches não é consistente.
switch
Vamos ver.switch
Outra forma de escrever o termo é sem expressão.
up = close > open // up = close < open
down = close < open
var upOfCount = 0
var downOfCount = 0
msgColor = switch
up =>
upOfCount += 1
color.green
down =>
downOfCount += 1
color.red
plotchar(up, title="up", char=str.tostring(upOfCount), location=location.abovebar, color=msgColor, overlay=true)
plotchar(down, title="down", char=str.tostring(downOfCount), location=location.belowbar, color=msgColor, overlay=true)
O exemplo de código de teste mostra que o switch irá corresponder aos blocos de código local verdadeiros em termos de execução de ramificação. Em geral, as condições de ramificação após a sentença de switch devem ser mutuamente recusadas. Isto significa que os blocos de código local de up e down não podem ser verdadeiros ao mesmo tempo.up = close > open // up = close < open
Além disso, é preciso ter cuidado para não escrever a chamada da função na filial do switch. A função não pode ser chamada em cada BAR, o que pode causar alguns problemas com a computação de dados.switch
“No exemplo, o braço de execução é definido e não é alterado durante a execução da estratégia”.)
返回值 = for 计数 = 起始计数 to 最终计数 by 步长
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
A função for é muito simples de usar, pois o loop for pode retornar um valor final (for) ou retornar vários valores, para que o loop for retorne um valor final (for).[a, b, c] como forma de a, b, c)
Usado no ciclo forbreak
Palavras-chave: quando executadobreak
O ciclo termina com a frase.
Usado no ciclo forcontinue
Palavras-chave: quando executadocontinue
Depois da frase, o ciclo ignora.continue
O código seguinte executa diretamente a próxima rodada de ciclo. A declaração for retorna o valor de retorno da última execução de ciclo. Se não houver nenhuma execução de código, retorna um valor nulo.
Aqui está um exemplo simples:
ret = for i = 0 to 10 // 可以增加by关键字修改步长,暂时FMZ不支持 i = 10 to 0 这样的反向循环
// 可以增加条件设置,使用continue跳过,break跳出
runtime.log("i:", i)
i // 如果这行不写,就返回空值,因为没有可返回的变量
runtime.log("ret:", ret)
runtime.error("stop")
for ... in
Há duas formas de sentenças, com o seguinte código de pseudo para ilustrar:
返回值 = for 数组元素 in 数组
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
返回值 = for [索引变量, 索引变量对应的数组元素] in 数组
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
A principal diferença entre as duas formas é o conteúdo que segue após a palavra-chave for, uma é usar uma variável como referência para um elemento da matriz. A outra é usar uma estrutura que contém uma variável de indexação, um subconjunto de uma variável do elemento da matriz para fazer referência.
testArray = array.from(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
for ele in testArray // 修改成 [i, ele]的形式:for [i, ele] in testArray , runtime.log("ele:", ele, ", i:", i)
runtime.log("ele:", ele)
runtime.error("stop")
Usar índices sempre que necessáriofor [i, ele] in testArray
Como se escreve?
Aplicações circulares
Quando você pode usar funções embutidas fornecidas pela linguagem Pine para fazer alguns cálculos de lógica circular, você pode usar a estrutura circular para escrever diretamente, ou você pode usar funções embutidas para processar. Vamos dar dois exemplos.
1 - Calcular a média
Usando um design de estrutura circular:
length = 5
var a = array.new(length)
array.push(a, close)
if array.size(a) >= length
array.remove(a, 0)
sum = 0
for ele in a
sum += ele
avg = sum / length
plot(avg, title="avg", overlay=true)
O exemplo usa a soma circular for, e então calcula a média.
Calcule a linha média diretamente com a função embutida:
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Funções embutidas diretamenteta.sma
Para calcular o indicador da linha média, é obviamente mais fácil usar a função embutida para calcular a linha média. A comparação no gráfico mostra que os resultados dos cálculos são totalmente consistentes.
2o, adição
Ou use o exemplo acima para ilustrar.
Usando um design de estrutura circular:
length = 5
var a = array.new(length)
array.push(a, close)
if array.size(a) >= length
array.remove(a, 0)
sum = 0
for ele in a
sum += ele
avg = sum / length
plot(avg, title="avg", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Para calcular a soma de todos os elementos de uma matriz, pode-se usar um loop ou uma função embutida.array.sum
Para calcular.
A soma é calculada diretamente com a função embutida:
length = 5
var a = array.new(length)
array.push(a, close)
if array.size(a) >= length
array.remove(a, 0)
plot(array.sum(a) / length, title="avg", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Os dados obtidos são mostrados na gráfica de acordo com o gráfico usado.
Então, se você pode fazer isso com funções embutidas, por que criar um loop? 1 . Para algumas operações do array, computação . 2 - Revisar o histórico, por exemplo, para descobrir quantos pontos altos do passado foram mais altos que os pontos altos do BAR atual. Como os pontos altos do BAR atual são conhecidos apenas no BAR em execução do script, é necessário um loop para retornar e analisar o BAR do passado. 3 A função embutida na linguagem Pine não consegue completar o cálculo do BAR passado.
while
A frase permite que o código da parte do loop continue a ser executado até que a condição de julgamento na estrutura while seja falsa.
返回值 = while 判断条件
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
As outras regras do while são semelhantes às do ciclo for, onde a última linha do bloco de código local do corpo do ciclo é um valor de retorno, que pode retornar vários valores. O ciclo é executado quando a “condição do ciclo” é verdadeira e o ciclo é interrompido quando a condição é falsa.
Eu ainda vou usar o exemplo da linha de equilíbrio:
length = 10
sma(data, length) =>
i = 0
sum = 0
while i < 10
sum += data[i]
i += 1
sum / length
plot(sma(close, length), title="sma", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Pode-se ver que o uso do while loop também é muito simples, e também pode-se projetar algumas lógicas de computação que não podem ser substituídas por funções embutidas, como o cálculo da multiplicação por grau:
counter = 5
fact = 1
ret = while counter > 0
fact := fact * counter
counter := counter - 1
fact
plot(ret, title="ret") // ret = 5 * 4 * 3 * 2 * 1
A definição de array na linguagem Pine é semelhante à definição de arrays em outras linguagens de programação. Uma array é uma matriz de dimensões. Normalmente, ela é usada para armazenar uma série contínua de dados. Arrays em que os dados individuais são armazenados são chamados de elementos de um array.[]
É preciso usararray.get()
earray.set()
A função 。 a ordem de indexação dos elementos na matriz é a seguinte: o primeiro elemento da matriz tem um índice de 0 e o seguinte tem um índice de 1 。
O que podemos dizer com um código simples:
var a = array.from(0)
if bar_index == 0
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1])
else if bar_index == 1
array.push(a, bar_index)
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1])
else if bar_index == 2
array.push(a, bar_index)
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1], ", 向前数2根BAR上的a,即a[2]值:", a[2])
else if bar_index == 3
array.push(a, bar_index)
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1], ", 向前数2根BAR上的a,即a[2]值:", a[2], ", 向前数3根BAR上的a,即a[3]值:", a[3])
else if bar_index == 4
// 使用array.get 按索引获取元素,使用array.set按索引修改元素
runtime.log("数组修改前:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))
array.set(a, 1, 999)
runtime.log("数组修改后:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))
usararray<int> a
、float[] b
Uma variável pode ser atribuída a uma matriz, declarando uma matriz ou declarando apenas uma variável, por exemplo:
array<int> a = array.new(3, bar_index)
float[] b = array.new(3, close)
c = array.from("hello", "fmz", "!")
runtime.log("a:", a)
runtime.log("b:", b)
runtime.log("c:", c)
runtime.error("stop")
Geralmente usado para a inicialização de variáveis de arrayarray.new
earray.from
Funções 。 Há muitas outras funções no idioma Pine que são semelhantes às do array.new em relação ao tipo:array.new_int()
、array.new_bool()
、array.new_color()
、array.new_string()
espere.
A palavra-chave var também pode funcionar com o modo de declaração de uma matriz, usando a palavra-chave var, uma matriz declarada é iniciada apenas na primeira linha BAR. Observamos por meio de um exemplo:
var a = array.from(0)
b = array.from(0)
if bar_index == 1
array.push(a, bar_index)
array.push(b, bar_index)
else if bar_index == 2
array.push(a, bar_index)
array.push(b, bar_index)
else if barstate.islast
runtime.log("a:", a)
runtime.log("b:", b)
runtime.error("stop")
Pode-se ver que as mudanças na matriz a são fixadas de forma contínua, sem serem realocadas. A matriz b é initializada em cada BAR.barstate.islast
Para impressão em tempo real, ainda há apenas um elemento, o valor 0。
Use array.get para obter os elementos que indicam a posição de indexação na matriz e use array.set para modificar os elementos que indicam a posição de indexação na matriz.
O primeiro parâmetro de array.get é o array a ser processado, e o segundo parâmetro é o índice especificado. O primeiro parâmetro de array.set é o conjunto a ser processado, o segundo é o índice especificado, e o terceiro é o elemento a ser escrito.
Para ilustrar, use o seguinte exemplo simples:
lookbackInput = input.int(100)
FILL_COLOR = color.green
var fillColors = array.new(5)
if barstate.isfirst
array.set(fillColors, 0, color.new(FILL_COLOR, 70))
array.set(fillColors, 1, color.new(FILL_COLOR, 75))
array.set(fillColors, 2, color.new(FILL_COLOR, 80))
array.set(fillColors, 3, color.new(FILL_COLOR, 85))
array.set(fillColors, 4, color.new(FILL_COLOR, 90))
lastHiBar = - ta.highestbars(high, lookbackInput)
fillNo = math.min(lastHiBar / (lookbackInput / 5), 4)
bgcolor(array.get(fillColors, int(fillNo)), overlay=true)
plot(lastHiBar, title="lastHiBar")
plot(fillNo, title="fillNo")
Este exemplo inicializa a cor de base verde, declara e inicializa um array para preservar a cor e, em seguida, confere uma transparência diferente ao valor da cor (usando a função color.new). Computação da classificação da cor, calculando a distância entre o valor máximo do BAR atual e o máximo de 100 ciclos de revisão. Quanto mais próximo o valor máximo do BAR atual dos 100 ciclos de revisão mais recentes, maior é a classificação e mais profunda é a correspondente quantidade de cores (baixa transparência).
Como percorrer uma matriz, podemos usar as expressões for/for in/while que aprendemos anteriormente.
a = array.from(1, 2, 3, 4, 5, 6)
for i = 0 to (array.size(a) == 0 ? na : array.size(a) - 1)
array.set(a, i, i)
runtime.log(a)
runtime.error("stop")
a = array.from(1, 2, 3, 4, 5, 6)
i = 0
while i < array.size(a)
array.set(a, i, i)
i += 1
runtime.log(a)
runtime.error("stop")
a = array.from(1, 2, 3, 4, 5, 6)
for [i, ele] in a
array.set(a, i, i)
runtime.log(a)
runtime.error("stop")
Os resultados são os mesmos em todas as três viagens.
Arrays podem ser declarados no âmbito global do script, ou no âmbito local da função ou da filial if
Para o uso de elementos em uma matriz, a seguinte maneira é equivalente, podemos ver através do exemplo a seguir que dois grupos de linhas são desenhados na tabela, dois em cada grupo, e os valores dos dois grupos de linhas são exatamente os mesmos.
a = array.new_float(1)
array.set(a, 0, close)
closeA1 = array.get(a, 0)[1]
closeB1 = close[1]
plot(closeA1, "closeA1", color.red, 6)
plot(closeB1, "closeB1", color.black, 2)
ma1 = ta.sma(array.get(a, 0), 20)
ma2 = ta.sma(close, 20)
plot(ma1, "ma1", color.aqua, 6)
plot(ma2, "ma2", color.black, 2)
1, função relacionada à operação de adição de um array:
array.unshift()
、array.insert()
、array.push()
。
array.remove()
、array.shift()
、array.pop()
、array.clear()
。
Nós usamos o exemplo a seguir para testar as funções de adição e subtração dessas matrizes.
a = array.from("A", "B", "C")
ret = array.unshift(a, "X")
runtime.log("数组a:", a, ", ret:", ret)
ret := array.insert(a, 1, "Y")
runtime.log("数组a:", a, ", ret:", ret)
ret := array.push(a, "D")
runtime.log("数组a:", a, ", ret:", ret)
ret := array.remove(a, 2)
runtime.log("数组a:", a, ", ret:", ret)
ret := array.shift(a)
runtime.log("数组a:", a, ", ret:", ret)
ret := array.pop(a)
runtime.log("数组a:", a, ", ret:", ret)
ret := array.clear(a)
runtime.log("数组a:", a, ", ret:", ret)
runtime.error("stop")
Aplicações de adição e remoção: Arrays as queues
Usando uma matriz, e algumas funções de adição e remoção da matriz, podemos construir uma estrutura de dados chamada “coordenada”. As coordenadas podem ser usadas para calcular a média móvel do preço do tick. Alguns colegas podem perguntar: “Por que construir uma estrutura de coordenadas?
Uma coordenada é uma estrutura frequentemente usada na programação, que possui as seguintes características:
Os elementos que entram primeiro na fila saem primeiro.
Isso garante que os dados existentes na fila sejam os mais recentes e que o comprimento da fila não se expanda indefinidamente (o código de expansão ilimitada só pode ser escrito ao meio-dia, pois isso pode causar problemas de madrugada e de noite).
O exemplo a seguir usa uma estrutura de coordenadas para registrar o preço de cada tick, calcular a média móvel em nível de tick e compará-la com a média móvel em nível de linha K em 1 minuto.
strategy("test", overlay=true)
varip a = array.new_float(0)
var length = 10
if not barstate.ishistory
array.push(a, close)
if array.size(a) > length
array.shift(a)
sum = 0.0
for [index, ele] in a
sum += ele
avgPrice = array.size(a) == length ? sum / length : na
plot(avgPrice, title="avgPrice")
plot(ta.sma(close, length), title="ta.sma")
Observe que quando declaramos um array, nós especificamos o modo de declaração e usamos a palavra-chavevarip
Assim, cada mudança de preço é registrada na matriz a.
Funções de cálculo:
array.avg()
Então vamos ter uma média de todos os elementos do conjunto.array.min()
O que é o menor elemento do conjunto?array.max()
Então, o que é o maior elemento de uma matriz?array.stdev()
Busque a diferença padrão de todos os elementos da matriz.array.sum()
Obter a soma de todos os elementos da matriz.
Funções relacionadas com a operação:
array.concat()
Combinação ou conexão de dois conjuntos.
array.copy()
Copiar uma matriz.
array.join
Conecte todos os elementos da matriz em uma string.
array.sort()
Classificação por ascensão ou descensão.
array.reverse()
Matriz invertida.
array.slice()
Tape a matriz.
array.includes()
Elemento de julgamento.
array.indexof()
Retorna o índice em que o valor do parâmetro foi introduzido pela primeira vez. Se este valor não for encontrado, retorna -1
array.lastindexof()
Encontre o valor da última vez que apareceu.
Exemplos de testes de funções relacionadas com o cálculo de matrizes:
a = array.from(3, 2, 1, 4, 5, 6, 7, 8, 9)
runtime.log("数组a的算数平均:", array.avg(a))
runtime.log("数组a中的最小元素:", array.min(a))
runtime.log("数组a中的最大元素:", array.max(a))
runtime.log("数组a中的标准差:", array.stdev(a))
runtime.log("数组a的所有元素总和:", array.sum(a))
runtime.error("stop")
Estas são as funções de cálculo de matrizes mais usadas.
Exemplos de funções operacionais:
a = array.from(1, 2, 3, 4, 5, 6)
b = array.from(11, 2, 13, 4, 15, 6)
runtime.log("数组a:", a, ", 数组b:", b)
runtime.log("数组a,数组b连接在一起:", array.concat(a, b))
c = array.copy(b)
runtime.log("复制一个数组b,赋值给变量c,变量c:", c)
runtime.log("使用array.join处理数组c,给每个元素中间增加符号+,连接所有元素结果为字符串:", array.join(c, "+"))
runtime.log("排序数组b,按从小到大顺序,使用参数order.ascending:", array.sort(b, order.ascending)) // array.sort函数修改原数组
runtime.log("排序数组b,按从大到小顺序,使用参数order.descending:", array.sort(b, order.descending)) // array.sort函数修改原数组
runtime.log("数组a:", a, ", 数组b:", b)
array.reverse(a) // 此函数修改原数组
runtime.log("反转数组a中的所有元素顺序,反转之后数组a为:", a)
runtime.log("截取数组a,索引0 ~ 索引3,遵循左闭右开区间规则:", array.slice(a, 0, 3))
runtime.log("在数组b中搜索元素11:", array.includes(b, 11))
runtime.log("在数组a中搜索元素100:", array.includes(a, 100))
runtime.log("将数组a和数组b连接,搜索其中第一次出现元素2的索引位置:", array.indexof(array.concat(a, b), 2), " , 参考观察 array.concat(a, b):", array.concat(a, b))
runtime.log("将数组a和数组b连接,搜索其中最后一次出现元素6的索引位置:", array.lastindexof(array.concat(a, b), 6), " , 参考观察 array.concat(a, b):", array.concat(a, b))
runtime.error("stop")
A linguagem Pine pode projetar funções personalizadas, geralmente com as seguintes regras:
barcolor()、 fill()、 hline()、plot()、 plotbar()、 plotcandle()
) não pode ser chamado dentro de uma função personalizada.
4 , funções podem ser escritas em uma única linha, multilínea. O valor de retorno da última frase é o valor de retorno da função atual, o valor de retorno pode ser devolvido na forma de um módulo.Também usamos funções personalizadas em tutoriais anteriores, por exemplo, funções personalizadas projetadas em linhas únicas:
barIsUp() => close > open
Esta função retorna se o BAR atual é o diagrama.
Concebido como uma função personalizada de várias linhas:
sma(data, length) =>
i = 0
sum = 0
while i < 10
sum += data[i]
i += 1
sum / length
plot(sma(close, length), title="sma", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
A função que nós mesmos realizamos com uma função personalizada chamada sma mediana linear.
Além disso, pode-se retornar um exemplo de função-custom para duas variáveis:
twoEMA(data, fastPeriod, slowPeriod) =>
fast = ta.ema(data, fastPeriod)
slow = ta.ema(data, slowPeriod)
[fast, slow]
[ema10, ema20] = twoEMA(close, 10, 20)
plot(ema10, title="ema10", overlay=true)
plot(ema20, title="ema20", overlay=true)
Uma função pode calcular uma linha rápida, uma linha lenta e dois indicadores de linha média EMA.
A função embutida pode ser facilmenteFMZ PINE Script DocumentárioConsulta no site.
As funções embutidas na linguagem Pine são classificadas:
1 , função de processamento de stringstr.
Série
2 Funções de processamento de valores de corcolor.
Série
Funções de entrada de parâmetrosinput.
Série
4. Funções de cálculo de indicadoresta.
Série
Funções de desenhoplot.
Série
6 Funções de processamento de arraysarray.
Série
7 Funções relacionadas a transaçõesstrategy.
Série
Funções matemáticasmath.
Série
9 , outras funções ((processamento de tempo, não-plot função de desenho de série),request.
Funções de série, funções de processamento de tipos, etc.)
strategy.
As funções de série são funções que usamos frequentemente na concepção de estratégias, e que estão relacionadas com a execução de operações de transação quando a estratégia é executada.
1、strategy.entry
strategy.entry
A função é uma função de encomenda que é muito importante quando escrevemos estratégias. Alguns dos seus principais parâmetros são:id
, direction
, qty
, when
espere.
parâmetro:
id
: pode ser entendido como um nome dado a uma posição de negociação para ser usado como referência. Pode ser citado como um id para cancelar, alterar ordens, liquidar posições.direction
Se a direção do pedido é fazer mais (comprar), o parâmetro é transmitido.strategy.long
Essa variável interna é transmitida se você for à falência.strategy.short
Esta variável é:qty
: especificar o volume de encomenda, se este parâmetro não for transmitido, será usado o volume de encomenda padrão.when
: condição de execução, você pode especificar este parâmetro para controlar se a operação de encomenda atual é acionada ou não.limit
Especifique o preço de limite da encomendastop
Preço de parada:strategy.entry
Detalhes da execução específica da funçãostrategy
O controle de configuração de parâmetros de uma chamada de função também pode ser feito por“Parâmetros de modelagem da biblioteca de classes de transação da linguagem Pine”Para mais detalhes sobre o controle de configuração e o controle de parâmetros de modelagem da biblioteca de classes de transação em linguagem Pine, consulte o documento em link.
Aqui está o foco.strategy
A funçãopyramiding
、default_qty_value
Parâmetros. Teste com o seguinte código:
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)
ema10 = ta.ema(close, 10)
findOrderIdx(idx) =>
if strategy.opentrades == 0
false
else
ret = false
for i = 0 to strategy.opentrades - 1
if strategy.opentrades.entry_id(i) == idx
ret := true
break
ret
if not findOrderIdx("long1")
strategy.entry("long1", strategy.long)
if not findOrderIdx("long2")
strategy.entry("long2", strategy.long, 0.2, when = close > ema10)
if not findOrderIdx("long3")
strategy.entry("long3", strategy.long, 0.2, limit = low[1])
strategy.entry("long3", strategy.long, 0.3, limit = low[1])
if not findOrderIdx("long4")
strategy.entry("long4", strategy.long, 0.2)
plot(ema10, title="ema10", color=color.red)
Início do código/*backtest ... */
A parte do pacote é a configuração de retroalimentação, para registrar informações como o tempo de configuração de retroalimentação no momento, para facilitar a delimitação, e não o código de estratégia.
No código:strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)
Quando nós designamospyramiding
Quando o parâmetro é 3, nós definimos o máximo de 3 vezes para o mesmo negócio. Então, no exemplo, quatro vezes.strategy.entry
A seguinte operação não foi executada uma vez.default_qty_value
O parâmetro é 0,1, então o ID é o de longitude1strategy.entry
O número de comandos de cada operação é o 0.1.strategy.entry
A função que nós especificamos quando chamamosdirection
São:strategy.long
A resposta é que os testes são pagos.
Atenção no códigostrategy.entry("long3", ...
A operação seguinte foi chamada duas vezes, para o mesmo ID: long3.strategy.entry
A operação de envio não deu resultado, segunda chamadastrategy.entry
A função é para modificar o pedido deste ID ((os dados exibidos no teste de retrospectiva também podem mostrar que o pedido abaixo do limite de preço foi modificado para 0.3)). Outra situação, por exemplo, se o primeiro pedido do ID for de 3 tons de comprimento, continue a usar o ID de 3 tons de comprimento.strategy.entry
Se a função for encomendada, então o valor da encomenda será acumulado no IDlong3.
2、strategy.close
strategy.close
A função é usada para definir a posição de entrada para a posição de entrada que identifica o ID. Os principais parâmetros são:id
,when
,qty
,qty_percent
。
parâmetro:
id
A identificação de entrada necessária para a liquidação é a que usamos.strategy.entry
O ID definido no momento da abertura da posição.when
Condições de execuçãoqty
Número de liquidações.qty_percent
Porcentagem de equilíbrioPara se familiarizar com os detalhes do uso desta função, veja um exemplo:
No código/*backtest ... */
É a informação de configuração do FMZ.COM International Station Retest, que pode ser removida, configurando o mercado, a variedade e o período de tempo que você precisa testar.
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
strategy("close Demo", pyramiding=3)
var enableStop = false
if enableStop
runtime.error("stop")
strategy.entry("long1", strategy.long, 0.2)
if strategy.opentrades >= 3
strategy.close("long1") // 多个入场订单,不指定qty参数,全部平仓
// strategy.close() // 不指定id参数,会平掉当前的持仓
// strategy.close("long2") // 如果指定一个不存在的id则什么都不操作
// strategy.close("long1", qty=0.15) // 指定qty参数平仓
// strategy.close("long1", qty_percent=50) // qty_percent设置50即为平掉long1标识仓位的50%持仓
// strategy.close("long1", qty_percent=80, when=close<open) // 指定when参数,修改为close>open就不触发了
enableStop := true
A estratégia de testes mostrou que a entrada foi feita três vezes seguidas, com IDs de entrada de 1 long e 1 long, e que a entrada foi feita usando o ID de entrada de 1 long e 1 long.strategy.close
Os diferentes resultados de uma função quando os diferentes parâmetros são ajustados para a posição de equilíbrio podem ser encontrados.strategy.close
Esta função não possui parâmetros para especificar o preço de pedido de liquidação. Esta função é usada principalmente para liquidação imediata a preços de mercado atuais.
3、strategy.close_all
strategy.close_all
A função é usada para nivelar todas as posições atuais, uma vez que os scripts de linguagem Pine possuem apenas uma direção, ou seja, se houver um sinal de ação oposto à direção da posição atual, a posição atual será nivelada e a posição será ativada de acordo com o sinal.strategy.close_all
Quando chamado, ele elimina todas as posições na direção atual.strategy.close_all
Os principais parâmetros da função são:when
。
parâmetro:
when
Condições de execuçãoO que podemos observar usando um exemplo:
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
strategy("closeAll Demo")
var enableStop = false
if enableStop
runtime.error("stop")
strategy.entry("long", strategy.long, 0.2, when=strategy.position_size==0 and close>open)
strategy.entry("short", strategy.short, 0.3, when=strategy.position_size>0 and close<open)
if strategy.position_size < 0
strategy.close_all()
enableStop := true
O código de teste começa com uma posição de 0…strategy.position_size==0
É verdade), então executa o ID como um longínquo longínquo quando ele atende às condições do parâmetro when.strategy.entry
Função de entrada: após ter várias posiçõesstrategy.position_size
Maior do que 0, então a função de entrada do ID para o short quebra-cabeça só pode ser executada, devido a posse atual de posições de muitos cabeças, este sinal de inverso de defesa que aparece neste momento pode levar a quebrar as posições de muitos cabeças e voltar a abrir. Em seguida, nós escrevemos em se condição quandostrategy.position_size < 0
Quando, ou seja, quando a posição de cabeça vazia é levada, a posição total da direção atual é eliminada. E a marcaenableStop := true
◦ Fazer com que a estratégia pare de ser executada para que o log possa ser observado.
Descobrirstrategy.close_all
Esta função não possui parâmetros para especificar o preço de pedido de liquidação. Esta função é usada principalmente para liquidação imediata a preços de mercado atuais.
4、strategy.exit
strategy.exit
A função é usada para a operação de liquidação de entrada para a posição, diferentemente da funçãostrategy.close
estrategy.close_all
A função é a liquidação imediata a preços de mercado atuais.strategy.exit
A função planeja a liquidação de acordo com a configuração dos parâmetros.
parâmetro:
id
: ID de pedido para esta lista de condições de liquidação.from_entry
: ID de entrada para especificar a operação de liquidação.qty
Número de liquidações.qty_percent
Percentagem de equilíbrio, faixa: 0 ~ 100 ◦profit
O objetivo de lucro, expresso em pontos.loss
O objetivo é parar os danos, em pontos.limit
A meta de lucro é definida pelo preço.stop
A meta de stop loss é definida pelo preço.when
Condições de execuçãoUse uma estratégia de teste para entender o uso de cada parâmetro.
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
args: [["RunMode",1,358374],["ZPrecision",0,358374]]
*/
strategy("strategy.exit Demo", pyramiding=3)
varip isExit = false
findOrderIdx(idx) =>
ret = -1
if strategy.opentrades == 0
ret
else
for i = 0 to strategy.opentrades - 1
if strategy.opentrades.entry_id(i) == idx
ret := i
break
ret
strategy.entry("long1", strategy.long, 0.1, limit=1, when=findOrderIdx("long1") < 0)
strategy.entry("long2", strategy.long, 0.2, when=findOrderIdx("long2") < 0)
strategy.entry("long3", strategy.long, 0.3, when=findOrderIdx("long3") < 0)
if not isExit and strategy.opentrades > 0
// strategy.exit("exitAll") // 如果仅仅指定一个id参数,则该退场订单无效,参数profit, limit, loss, stop等出场条件也至少需要设置一个,否则也无效
strategy.exit("exit1", "long1", profit=50) // 由于long1入场订单没有成交,因此ID为exit1的出场订单也处于暂待状态,直到对应的入场订单成交才会放置exit1
strategy.exit("exit2", "long2", qty=0.1, profit=100) // 指定参数qty,平掉ID为long2的持仓中0.1个持仓
strategy.exit("exit3", "long3", qty_percent=50, limit=strategy.opentrades.entry_price(findOrderIdx("long3")) + 1000) // 指定参数qty_percent,平掉ID为long3的持仓中50%的持仓
isExit := true
if bar_index == 0
runtime.log("每点价格为:", syminfo.mintick) // 每点价格和Pine语言模板参数上「定价货币精度」参数设置有关
Usando o teste de retorno do modelo de preço em tempo real, a estratégia de teste começa a executar três operações de entrada:strategy.entry
Função), long1 deliberadamente definidolimit
Parâmetros, o preço do pendrive é de 1 para que ele não possa ser transacionado. Então teste a função de saída da condiçãostrategy.exit
。 Usou paradas por pontos, paradas por preços, paradas por posições de quantidade fixa, paradas por percentagem. 。 Considerando que o exemplo de extensão apenas demonstra paradas. 。 A operação de parada de perda também é equivalente.strategy.exit
A função também possui parâmetros de tracking stop loss mais complexos:trail_price
、trail_points
、trail_offset
Pode-se também testar o seu uso neste exemplo.
5、strategy.cancel
strategy.cancel
Funções usadas para cancelar / desativar todos os comandos de lista de pré-enrolamento. Estas funçõesstrategy.order
, strategy.entry
, strategy.exit
Pode gerar entrada ID. O principal parâmetro da função é:id
、when
。
parâmetro:
id
A identificação de entrada a ser cancelada:when
Condições de execuçãoEsta função é muito bem compreendida e é usada para cancelar ordens de entrada que não foram feitas.
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
strategy("strategy.cancel Demo", pyramiding=3)
var isStop = false
if isStop
runtime.error("stop")
strategy.entry("long1", strategy.long, 0.1, limit=1)
strategy.entry("long2", strategy.long, 0.2, limit=2)
strategy.entry("long3", strategy.long, 0.3, limit=3)
if not barstate.ishistory and close < open
strategy.cancel("long1")
strategy.cancel("long2")
strategy.cancel("long3")
isStop := true
6、strategy.cancel_all
strategy.cancel_all
Funções estrategy.cancel
A função é semelhante a: cancelar / desativar todas as ordens de lista pré-encomendada: pode ser especificadawhen
Parâmetros
parâmetro:
when
Condições de execução”`pine /*backtest start: 2022-07-03 00:00:00 end: 2022-07-09 00:00:00 period: 1d basePeriod: 1h exchanges: [{“eid”:“Binance”,“currency”:“BTC_USDT”}] */
strategy(“strategy.cancel Demo”, pyramiding=3)
var isStop = false if isStop runtime.error(“stop”)
strategy.entry(“long1”, strategy.long, 0.1, limit=1) strategy.entry(“long2”, strategy.long,