[TOC]
Acompanhado de um vídeo tutorial: É muito difícil entrar em um negócio quantificado?
A plataforma de negociação quantitativa do inventor suporta a estratégia de programação da linguagem Pine, suporta a retrospectiva, a estratégia de linguagem Pine em tempo real e é compatível com versões mais baixas da linguagem Pine.Praça da EstratégiaO blog é uma coleção de várias estratégias e scripts de Pine.
O FMZ não apenas suporta a linguagem Pine, mas também suporta o poderoso recurso de gráficos da linguagem Pine. Os recursos da plataforma FMZ, as ferramentas práticas e eficientes e fáceis de gerenciar, também aumentam a praticidade da estratégia e do script do Pine. O FMZ é baseado na compatibilidade com a linguagem Pine, e também faz um certo grau de extensão, otimização e corte na linguagem Pine.
A seguir, um breve resumo de algumas das diferenças mais evidentes:
//@version
E o código começastrategy
、indicator
A frase não é obrigatória e o FMZ não o suporta por enquantoimport
Importaçãolibrary
função.O blogueiro também escreveu sobre a estratégia do Facebook:
//@version=5
indicator("My Script", overlay = true)
src = close
a = ta.sma(src, 5)
b = ta.sma(src, 50)
c = ta.cross(a, b)
plot(a, color = color.blue)
plot(b, color = color.black)
plotshape(c, color = color.red)
Ou então:
//@version=5
strategy("My Strategy", overlay=true)
longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
if (longCondition)
strategy.entry("My Long Entry Id", strategy.long)
shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))
if (shortCondition)
strategy.entry("My Short Entry Id", strategy.short)
Em FMZ, pode ser simplificado como:
src = close
a = ta.sma(src, 5)
b = ta.sma(src, 50)
c = ta.cross(a, b)
plot(a, color = color.blue, overlay=true)
plot(b, color = color.black, overlay=true)
plotshape(c, color = color.red, overlay=true)
Ou:
longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
if (longCondition)
strategy.entry("My Long Entry Id", strategy.long)
shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))
if (shortCondition)
strategy.entry("My Short Entry Id", strategy.short)
Algumas configurações relacionadas a transações são definidas pelo parâmetro “Pine language transaction class library” na interface de estratégia do FMZ.
strategy
Função decalc_on_every_tick
Parâmetros para definir o script de estratégia para executar a lógica da estratégia em tempo real a cada mudança de preçocalc_on_every_tick
Os parâmetros devem ser definidos comotrue
Por padrãocalc_on_every_tick
O parâmetro éfalse
A lógica da estratégia só é executada quando a linha K BAR atual da estratégia está completa.
No FMZ, é configurado através dos parâmetros do modelo “Pine Language Transaction Classroom”.Precisa-se de um controle de precisão numérica na FMZ, como o preço e a quantidade de encomendas no momento da execução da estratégia Na visão de negociação, como só é possível fazer testes em simulação, não há problemas de precisão de encomendas em tempo real. Na FMZ, é possível executar a estratégia Pine em tempo real. Então, a estratégia precisa ser flexível para especificar a precisão do preço da variedade de negociação e a precisão da quantidade de encomendas. Essas configurações de precisão controlam o número pequeno de dados relevantes, evitando que os dados não atendam aos requisitos de notificação da bolsa e, portanto, não possam ser encomendados.
Código de contrato a prazo
O tipo de transação no FMZ, se for um contrato, tem duas propriedades: “contract pair” e “contract code”. Além da necessidade de definir um par de transação explicitamente no disco e na retrospectiva, também é necessário definir um código de contrato específico no parâmetro “variety code” do modelo “Pine language trading library”. Por exemplo, o contrato de permanência é preenchidoswap
, Código de contrato para ver se a troca de operação específica tem esse contrato. Por exemplo, todos os contratos trimestrais de algumas transações podem ser preenchidos aquiquarter
Estes códigos de contratos coincidem com os códigos de contratos futuros definidos na documentação da API de linguagem Javascript/python/c++ da FMZ.
Outras configurações, como a quantidade mínima, a quantidade padrão, etc., podem ser encontradas na documentação do idioma Pine sobre“Pine Language Exchange” (em inglês)Introdução aos parâmetros.
runtime.debug
、runtime.log
、runtime.error
Função de extensão FMZ, usada para a delimitação .Três funções foram adicionadas à plataforma FMZ para a delimitação.
runtime.debug
: Esta função não é geralmente usada para imprimir informações de variáveis no console.
runtime.log
Output content in the log. Funções específicas da linguagem FMZ PINE.
runtime.log(1, 2, 3, close, high, ...),可以传多个参数。
runtime.error
: quando chamado, pode causar erros de execução e trazer uma mensagem de erro especificada no parâmetro de mensagem.
runtime.error(message)
4 - Expansão em parte da função gráficaoverlay
parâmetro
Função de desenho em linguagem Pine no FMZplot
、plotshape
、plotchar
Aumentou.overlay
Suporte de parâmetros, permitindo especificar imagens no mapa principal ou no mapa secundário.overlay
configurartrue
Desenho no mapa principal, configurado parafalse
Desenhar em subdivisões. Permite que a estratégia Pine em FMZ seja executada ao mesmo tempo que o mapa principal e o subdivisão.
syminfo.mintick
Valor de variável embutidasyminfo.mintick
A variável embutida é definida como o valor de medida mínimo da variedade atual.Oferta Firme/Testes retrospectivosO valor pode ser controlado pela precisão de precificação monetária, um parâmetro do modelo na interface “Pine Language Transaction Classroom”. A definição de precisão monetária 2 significa que o preço é exato para o segundo lugar de um número menor quando o preço é negociado, com uma mínima variação de 0,01syminfo.mintick
O valor de um valor de 0,01 é 0.01 .
Por exemplo: o preço de encomenda é de 8000, a direção de venda, a quantidade é de 1 mão, o preço médio após a transação não é de 8000, é inferior a 8000, o custo inclui a taxa de processamento.
Quando começamos a aprender o básico da linguagem Pine, talvez não estejamos familiarizados com as instruções e a gramática do código de alguns exemplos. Não importa se não entendemos ou não, podemos primeiro familiarizar-nos com os conceitos, entender o objetivo do teste, ou consultar a documentação da linguagem Pine da FMZ para ver as instruções.
Quando se inicia a aprendizagem da linguagem Pine, é muito necessário entender os conceitos relacionados, como o processo de execução de scripts da linguagem Pine. A estratégia da linguagem Pine é baseada em gráficos e pode ser entendida como uma série de cálculos e operações, executadas na tabela em ordem cronológica, a partir dos primeiros dados já carregados.bar_index
Referência ao valor de índice da linha K Bar atual na execução do script Pine.
plot(bar_index, "bar_index")
plot
A função é uma das funções que mais usaremos no futuro. É muito simples de usar, é apenas desenhar uma linha no gráfico com base nos parâmetros de entrada, e os dados são:bar_index
A linha é denominadabar_index
。 A linha chamada bar_index na primeira barra tem um valor de 0 e aumenta 1 。 à medida que a barra aumenta para a direita.
Dependendo da configuração da estratégia, o modelo de execução da estratégia é diferente.收盘价模型
e实时价模型
◦ O conceito de modelo de preço de fechamento, modelo de preço em tempo real, já foi apresentado anteriormente.
Quando o código de estratégia é executado, o ciclo do atual Bar de linha K é executado completamente. Quando o K é fechado, o ciclo de linha K está terminado.
Quando o código da estratégia é executado, a barra de linha K atual, seja ela fechada ou não, executa a lógica da estratégia de pin em cada mudança de movimento, e o sinal de transação acionado é executado imediatamente.
Quando a estratégia da linguagem Pine é executada de esquerda para direita no gráfico, a linha K do gráfico é dividida em历史Bar
e实时Bar
- Não.
Quando a estratégia é configurada como um “modelo de preço real” e começa a ser executada, todas as barras K do gráfico, exceto a barra K na parte direita, são历史Bar
A lógica da estratégia em cada raiz历史Bar
Executar apenas uma vez.
Quando a estratégia é definida como um “modelo de preço de fechamento” e começa a ser executada, todas as barras do gráfico são历史Bar
A lógica da estratégia em cada raiz历史Bar
Executar apenas uma vez.
Baseado no cálculo da barra de histórico: O código da estratégia é executado uma vez no estado de fechamento da barra de histórico, e o código da estratégia continua a ser executado na próxima barra de histórico até que todas as barras de histórico sejam executadas uma vez.
Quando a estratégia é executada na última linha K Bar à direita, a barra é a barra do tempo real. Quando a barra do tempo real é fechada, a barra torna-se uma barra do tempo real passada (transformando-se em uma barra do tempo histórico). A direita do gráfico gera uma nova barra do tempo real.
Quando a estratégia é configurada como um “modelo de preço em tempo real” e começa a ser executada, uma lógica de estratégia é executada em cada mudança de comportamento na barra em tempo real. Quando a estratégia é definida como “modelo de preço de fechamento” e começa a ser executada, o gráfico não exibe a barra real.
Baseado em cálculos em tempo real do Bar:
Se a estratégia for configurada como um gráfico de “modelo de preço de fechamento” e não for exibida a barra em tempo real, o código da estratégia será executado apenas uma vez no fechamento da barra atual.
Se a estratégia é definida como “modelo de preço de parada real”, o cálculo na barra de tempo real e o histórico na barra de tempo real são completamente diferentes. Cada mudança de comportamento na barra de tempo real é executada por um código de estratégia.high
、low
、close
No Bar histórico é certo, no Bar em tempo real, esses valores podem mudar a cada vez que a situação muda. Portanto, os indicadores e outros dados calculados com base nesses valores também podem mudar em tempo real.close
O preço é sempre o mais atualizado e o preço é sempre o mais baixo.high
elow
Sempre representa o máximo máximo e o mínimo mínimo atingidos desde o início da barra atual. Estas variáveis embutidas representam o valor final da última atualização da barra.
Mecanismos de reversão da execução da estratégia no Bar em tempo real (modelo de preço em tempo real): Quando executado em Bar em tempo real, cada nova geração da estratégia executa uma variável redefinida pelo usuário anterior, chamada de reversão. Para entender o mecanismo de reversão com um exemplo, vamos testar o código.
Perceber:
/*backtest
...
..
.
*/
O pacote contém informações de configuração de retrospectiva armazenadas em código na plataforma FMZ.
/*backtest
start: 2022-06-03 09:00:00
end: 2022-06-08 15:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/
var n = 0
if not barstate.ishistory
runtime.log("n + 1之前, n:", n, " 当前bar_index:", bar_index)
n := n + 1
runtime.log("n + 1之后, n:", n, " 当前bar_index:", bar_index)
plot(n, title="n")
Nós só examinamos cenas executadas em tempo real no Bar, então usamosnot barstate.ishistory
A restrição de expressão é somente aplicada à variável n em tempo real no Bar e é usada antes e depois de executar a operação de agregaçãoruntime.log
A função de saída de informações no log da estratégia. A partir do uso da função de gráficoplot
A curva n desenhada pode ser vista como sempre 0 quando a estratégia está na barra de histórico. A operação n + 1 é acionada quando executada na barra de tempo real, e a operação n + 1 é executada em cada rodada de execução da estratégia na barra de tempo real. Pode ser observado a partir da informação do log que a cada rodada de execução do código da estratégia n é reinstalado como o valor que a estratégia de execução da barra de tempo real anterior finalmente enviou.
Para resumir: 1 Quando a estratégia começa a ser executada na barra de tempo real, um código de estratégia é executado para cada atualização de situação. 2. Quando executado na barra de tempo real, a variável é revertida antes de cada código de política executado. 3 Quando executado na barra de tempo real, a variável é submetida uma vez na atualização do fechamento.
Uma vez que os dados são rebocados, as operações de desenho, como as curvas no gráfico, também podem causar um redesenho, por exemplo, se modificarmos o código de teste que acabamos de fazer, o teste em disco rígido:
var n = 0
if not barstate.ishistory
runtime.log("n + 1之前, n:", n, " 当前bar_index:", bar_index)
n := open > close ? n + 1 : n
runtime.log("n + 1之后, n:", n, " 当前bar_index:", bar_index)
plot(n, title="n")
Imagem do momento A
Imagem do momento B
A única coisa que mudamos foi a seguinte frase:n := open > close ? n + 1 : n
, o Bar real atual é negativo ((ou seja, o preço de abertura é superior ao preço de fechamento) só quando a n acumula 1 ≠. Pode ser visto no primeiro gráfico ((momento A) porque o preço de abertura era superior ao preço de fechamento ((o sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de um sinal de
A seguir, vamos examinar as variáveis das funções da linguagem Pine. De acordo com a descrição de alguns dos tutoriais do Pine, as variáveis da função diferem das variáveis fora da função da seguinte maneira:
O histórico das variáveis de série usadas na função Pine é criado por cada chamada contínua da função. Se a função não for chamada em cada coluna do script executado, isso levará a uma diferença entre os valores de história do bloco interno e externo da função. Portanto, se a função não for chamada em cada coluna, a série que utiliza o mesmo valor de índice dentro e fora da função não irá citar o mesmo ponto de história.
Não importa, vamos entender isso com um código de teste que está sendo executado no FMZ:
/*backtest
start: 2022-06-03 09:00:00
end: 2022-06-08 15:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/
f(a) => a[1]
f2() => close[1]
oneBarInTwo = bar_index % 2 == 0
plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A")
plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
plot(close[2], title = "close[2]", color = color.red, overlay = true)
plot(close[1], title = "close[1]", color = color.green, overlay = true)
Captura de imagem da detecção em funcionamento
O código de teste é simples, e visa examinar os dados citados de duas maneiras:f(a) => a[1]
ef2() => close[1]
。
f(a) => a[1]
A forma como a função retorna no final usando os parâmetros:a[1]
。
f2() => close[1]
Utilização direta de variáveis embutidasclose
A função é a última que retorna.close[1]
。
[]
O símbolo é usado para referenciar o valor histórico de uma variável de uma série de dados, close[1] é uma referência ao preço de fechamento de uma barra anterior ao preço de fechamento atual. Nosso código de teste desenhou quatro tipos de dados no gráfico:
plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A")
Desenhe um caractere A, colorido em vermelho, quando oneBarInTwo for verdadeiro, e a posição desenhada (no eixo Y) é:f(close)
Retornará o valor:
plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
Desenhe um caractere em B, colorido em verde, quando oneBarInTwo é verdadeiro, e a posição desenhada (no eixo Y) é:f2()
Retornará o valor:
plot(close[2], title = "close[2]", color = color.red, overlay = true)
A linha, colorida em vermelho, é desenhada na posição ((no eixo Y) como:close[2]
Ou seja, o preço de fechamento no Bar atual na 2a linha à frente (a 2a linha à esquerda).
plot(close[1], title = "close[1]", color = color.green, overlay = true)
A linha, colorida em verde, é desenhada na posição (no eixo Y):close[1]
Ou seja, o preço de fechamento do Bar atual na 1a raiz à esquerda.
A retrospectiva de funcionamento através da estratégia pode ser visto no screenshot, embora a função usada para marcar o desenho Af(a) => a[1]
Funções usadas para marcar e desenhar Bf2() => close[1]
Todos são usados.[1] para referenciar dados históricos da série de dados, mas a posição dos marcadores “A” e “B” no gráfico é completamente diferente. A posição do marcador “A” sempre cai na linha vermelha, ou seja, o código da estratégiaplot(close[2], title = "close[2]", color = color.red, overlay = true)
A linha que ele desenhou e os dados que ele usou foram:close[2]
。
A razão é que o índice através da barra de linha K, ou seja, a variável embutidabar_index
Calcular se a marca “A” e “B” deve ser desenhada. A marca “A” e “B” não devem ser desenhadas em cada barra de linha K.f(a) => a[1]
Se a função não for chamada em cada Bar, o valor que será citado dessa maneira será relacionado à funçãof2() => close[1]
Este método cita valores diferentes, mesmo que ambos usem[1] com o mesmo índice).
Para ilustrar, um exemplo simples:
res = close > close[1] ? ta.barssince(close < close[1]) : -1
plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)
Vamos chamar a função de código.ta.barssince(close < close[1])
Escrever em um operador triangularcondition ? value1 : value2
Isso levou a que apenasclose > close[1]
A função ta.barssince.ta.barssince
A função é calculada a partir da última vezclose < close[1]
Número de linhas K criadas. Quando a função ta.barssince é chamada, é sempre close > close[1], ou seja, o preço de fechamento atual é maior que o preço de fechamento do Bar anterior, quando a função ta.barssince é chamada com a condição close < close[1] não foi criado, e não foi criado na última vez.
ta.barssince: Quando chamada, a função retorna na。 se esta condição nunca foi satisfeita antes da linha K atual.
Conforme mostrado na figura:
Então, quando desenhamos um gráfico, apenas desenhamos dados quando a variável res tem um valor ((-1) }}.
Para evitar esse problema, nós apenas usamosta.barssince(close < close[1])
A chamada de função é extraída do operador triangular e escrita no exterior de qualquer possível sub-branche condicional. Ela executa o cálculo em cada linha K Bar.
a = ta.barssince(close < close[1])
res = close > close[1] ? a : -1
plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)
O conceito de sequência de tempo é muito importante na linguagem Pine, e é um conceito que temos que entender quando aprendemos a linguagem Pine. A sequência de tempo não é um tipo, mas sim uma estrutura básica para armazenar valores contínuos de variáveis ao longo do tempo. Sabemos que o script Pine é baseado em gráficos, e o conteúdo mais básico exibido nos gráficos é o gráfico de linha K.open
É uma variável interna da linguagem Pine, construída para armazenar a sequência de tempo do preço de abertura de cada linha K de Bar. Pode ser interpretada comoopen
Esta estrutura de sequência de tempo representa o preço de abertura de todas as barras de linha K no diagrama K atual, desde o primeiro Bar no início até o Bar executado no script atual. Se o diagrama K atual for de um período de 5 minutos, então nós referimos o código de estratégia do Pine (ou usamos)open
É o preço de abertura da barra de linha K na execução atual do código da estratégia. É necessário usar o valor de abertura da barra de linha K para referenciar o valor histórico na sequência de tempo.[]
O operador é usado quando a estratégia Pine é executada em uma barra de linha K.open[1]
Indicar referênciaopen
O preço de abertura do Bar de linha K anterior executado pelo script atual na sequência de tempo (ou seja, o preço de abertura do ciclo de linha K anterior).
ta.cum
Por exemplo: ta.cum
Cumulative (total) sum of `source`. In other words it's a sum of all elements of `source`.
ta.cum(source) → series float
RETURNS
Total sum series.
ARGUMENTS
source (series int/float)
SEE ALSO
math.sum
Código de teste:
v1 = 1
v2 = ta.cum(v1)
plot(v1, title="v1")
plot(v2, title="v2")
plot(bar_index+1, title="bar_index")
Há muitas semelhanças.ta.cum
Essa função embutida pode processar dados diretamente na sequência de tempo, comota.cum
É somar os valores correspondentes das variáveis de entrada em cada barra de linha K, e depois usamos um gráfico para facilitar a compreensão.
O processo de execução da estratégia é a variável interna bar_index | - | - | - | - | A estratégia é executada na primeira linha de K-bar, onde 0 é a raiz de 1 e 1 é a raiz de 1. A estratégia é executada na linha K2 Bar 1 1 2 A estratégia é executada na terceira raiz K. |…|…|…|…| A estratégia é executada em N+1 raiz K.
Pode-se ver que, na verdade, v1, v2 e até mesmo bar_index são estruturas de sequência de tempo, com dados correspondentes em cada barra. Este código de teste não se diferencia entre o “modelo de preço em tempo real” ou o “modelo de preço de encerramento” apenas para mostrar o Bar real no gráfico. Para medir a velocidade, usamos o teste de retorno do “modelo de preço de encerramento”.
Porque v1 é igual a 1 em cada barra.ta.cum(v1)
A função é executada na primeira linha de K, Bar, e, como só existe a primeira linha de Bar, o resultado é 1, atribuindo o valor à variável v2。
Quandota.cum(v1)
Quando executado na segunda linha K Bar, já existem 2 linhas K Bar ((a primeira correspondente à variável interna bar_index é 0, a segunda correspondente à variável interna bar_index é 1), então o resultado é 2, atribuindo o valor à variável v2, e assim por diante. Na verdade, pode-se observar que v2 é o número de linhas K Bar no gráfico, já que o índice das linhas Kbar_index
Então isso é a partir de zero.bar_index + 1
Na verdade, é o número de linhas de K. O gráfico de observação também mostra as linhas.v2
ebar_index
É verdade.
Também posso usarta.cum
A função embutida calcula a soma dos preços de fechamento de todas as barras no gráfico atual, e então pode ser escrita apenas como:ta.cum(close)
, quando a estratégia é executada na barra de tempo real do lado direitota.cum(close)
O resultado do cálculo é a soma dos preços de fechamento de todas as barras no gráfico (sem a operação para o lado mais à direita, somando-se apenas à barra atual).
As variáveis de uma sequência de tempo também podem ser calculadas usando operadores, como o código:ta.sma(high - low, 14)
A variável interna.high
(o preço máximo da linha K Bar) menoslow
(Preço mínimo do K-Line Bar), uso finalta.sma
A função busca a média.
v1 = ta.highest(high, 10)[1]
v2 = ta.highest(high[1], 10)
plot(v1, title="v1", overlay=true)
plot(v2, title="v2", overlay=true)
O código de teste foi executado durante a retomada e pode ser observadov1
ev2
Se os valores dos números são idênticos, as linhas desenhadas no gráfico também se sobrepõem completamente. O resultado do cálculo de uma chamada de função deixará um rastro de valores na sequência de tempo, como o códigota.highest(high, 10)[1]
Dentre eles,ta.highest(high, 10)
O resultado da chamada de uma função também pode ser usado[1] para citar seu valor histórico.ta.highest(high, 10)
O resultado é o seguinte:ta.highest(high[1], 10)
Por isso.ta.highest(high[1], 10)
eta.highest(high, 10)[1]
É a mesma coisa.
Avaliar a informação de saída usando outra função gráfica:
a = ta.highest(close, 10)[1]
b = ta.highest(close[1], 10)
plotchar(true, title="a", char=str.tostring(a), location=location.abovebar, color=color.red, overlay=true)
plotchar(true, title="b", char=str.tostring(b), location=location.belowbar, color=color.green, overlay=true)
Pode-se ver os valores das variáveis a e b na sequência de tempo mostrados acima e abaixo da correspondente barra. Este código de desenho pode ser mantido durante o aprendizado, pois pode ser necessário frequentemente a saída de informações no gráfico para observação durante testes e experimentos.
Na parte inicial do tutorial, resumimos algumas diferenças entre o uso da linguagem Pine no FMZ e o uso da linguagem Pine no Trading View.indicator()
、strategy()
E, temporariamente, não.library()
É claro que, para ser compatível com as versões anteriores do script Pine, a estratégia foi escrita com coisas como://@version=5
,indicator()
,strategy()
Também é possível. Algumas configurações de política também podem ser feitas emstrategy()
Configuração de parâmetros na função.
<version>
<declaration_statement>
<code>
<version>
Informações de controle de versão podem ser omitidas.
Língua Pine//
Como notação de linha única, a notação de linha é ampliada pela FMZ, uma vez que a linguagem Pine não possui notação de linha múltipla./**/
Para notas de várias linhas.
As linhas de um script que não são comentários ou instruções do compilador são sentenças, que implementam o algoritmo do script. Uma sentença pode ser um desses conteúdos.
if
,for
,while
ouswitch
Estrutura de equivalênciaAs frases podem ser organizadas de várias maneiras.
空格
ou制表符
Comece (tabulação) O primeiro caractere deles também deve ser o primeiro caractere da linha As linhas que começam na primeira posição da linha, por definição, fazem parte do alcance global do script local block
Um bloco local deve ser encolhido em um marcador ou em quatro espaços (caso contrário, será analisado como uma sequência da linha anterior de código, ou seja, julgado como um contínuo da linha anterior de código), e cada bloco local define um alcance local diferente.Por exemplo, incluindo três blocos locais, um na declaração de função personalizada e dois usando a estrutura if na declaração de variável, com o seguinte código:
indicator("", "", true) // 声明语句(全局范围),可以省略不写
barIsUp() => // 函数声明(全局范围)
close > open // 本地块(本地范围)
plotColor = if barIsUp() // 变量声明 (全局范围)
color.green // 本地块 (本地范围)
else
color.red // 本地块 (本地范围)
runtime.log("color", color = plotColor) // 调用一个内置函数输出日志 (全局范围)
As linhas longas podem ser divididas em várias linhas, ou “enroladas”. As linhas enroladas devem ser encolhidas em qualquer número de espaços, desde que não sejam múltiplos de 4.
a = open + high + low + close
Pode ser embalado como ((observe que o número de espaços em cada linha não é um múltiplo de 4):
a = open +
high +
low +
close
Uma chamada longa de plot ((() pode ser embalada como ▽.
close1 = request.security(syminfo.tickerid, "D", close) // syminfo.tickerid 当前交易对的日线级别收盘价数据系列
close2 = request.security(syminfo.tickerid, "240", close) // syminfo.tickerid 当前交易对的240分钟级别收盘价数据系列
plot(ta.correlation(close, open, 100), // 一行长的plot()调用可以被包装
color = color.new(color.purple, 40),
style = plot.style_area,
trackprice = true)
A frase na declaração de função definida pelo usuário também pode ser empacotada. No entanto, como o bloco local deve começar gramaticalmente com uma contração (((4 espaços ou 1 símbolo), quando dividido para a linha seguinte, a parte de continuação da frase deve começar com uma contração ou mais (((não é igual ao múltiplo de 4 espaços)).
test(c, o) =>
ret = c > o ?
(c > o+5000 ?
1 :
0):
(c < o-5000 ?
-1 :
0)
a = test(close, open)
plot(a, title="a")
Antes de entendermos a variável, devemos primeiro entender o conceito de um identificador de barra. O identificador de barra comum é usado comofunçãoeVariaçõesO nome de uma função é usado para nomear uma variável.funçãoComo veremos em outros tutoriais, primeiro aprendemos o símbolo de identificação de um alfinete: 。
(A-Z)
Ou em letras minúsculas.(a-z)
Letras ou sublinhados(_)
Início, como o primeiro caractere do identificador.Por exemplo, o identificador com os seguintes nomes:
fmzVar
_fmzVar
fmz666Var
funcName
MAX_LEN
max_len
maxLen
3barsDown // 错误的命名!使用了数字字符作为标识符的开头字符
Como a maioria das linguagens de programação, a linguagem Pine também tem recomendações de escrita. Geralmente, é recomendado quando se nomeia um identificador:
// 命名变量、常量
GREEN_COLOR = #4CAF50
MAX_LOOKBACK = 100
int fastLength = 7
// 命名函数
zeroOne(boolValue) => boolValue ? 1 : 0
Os operadores são alguns símbolos de operação usados em linguagens de programação para construir expressões, enquanto expressões são regras de cálculo projetadas para algum tipo de computação quando escrevemos uma estratégia. Os operadores da linguagem Pine são classificados por função como:
Operadores de atribuição de valor, operadores de aritmética, operadores de comparação, operadores lógicos,? :
Os operadores de tríade.[]
O operador de referência histórica.
O operador aritmético*
Por exemplo, para distinguir o tipo de problema causado pelo resultado do operador de linguagem Pine no Trading View, há o seguinte código de teste:
//@version=5
indicator("")
lenInput = input.int(14, "Length")
factor = year > 2020 ? 3 : 1
adjustedLength = lenInput * factor
ma = ta.ema(close, adjustedLength) // Compilation error!
plot(ma)
O erro de compilação é causado por um erro de compilação de um script executado no Trading View.adjustedLength = lenInput * factor
Depois da multiplicação, temosseries int
Tipo (série), no entantota.ema
O segundo parâmetro da função não suporta esse tipo de função. No entanto, não há restrições rigorosas desse tipo no FMZ, e o código acima pode funcionar normalmente.
A seguir, vamos ver o uso de vários operadores.
Existem dois tipos de operadores de atribuição:=
、:=
A partir de agora, você pode fazer o que você quiser, mas não é o que você quer fazer.
=
O operador é usado para atribuir um valor a uma variável quando esta é iniciada ou declarada.=
Inicialização, declaração e atribuição de valor de uma variável começam com esse valor em cada barra subsequente. Estas são declarações de variáveis válidas:
a = close // 使用内置变量赋值给a
b = 10000 // 使用数值赋值
c = "test" // 使用字符串赋值
d = color.green // 使用颜色值赋值
plot(a, title="a")
plot(b, title="b")
plotchar(true, title="c", char=str.tostring(c), color=d, overlay=true)
Percebera = close
Declaração de atribuição, onde a variável a em cada Bar é o preço de fechamento atual do Bar (closed) ⋅ outras variáveisb
、c
、d
É invariável e pode ser testado em um sistema de feedback no FMZ, e os resultados podem ser vistos em um gráfico.
:=
Usado para atribuir valores a variáveis existentes, pode ser entendido simplesmente como o uso de:=
Os operadores são usados para modificar o valor de uma variável declarada e inicializada.
Se for usado:=
Um operador atribui um valor a uma variável não iniciada ou declarada, gerando erros, como:
a := 0
Então,:=
Os operadores de atribuição são geralmente usados para re-atribuir valores a variáveis já existentes, como:
a = close > open
b = 0
if a
b := b + 1
plot(b)
A julgar seclose > open
(ou seja, o BAR atual é a linha do sol), a variável é o valor verdadeiro (true) executa o código no bloco local da declaração ifb := b + 1
, usando o operador de atribuição:=
Re-atribuir a b, acrescentando um 1 ◦ e, em seguida, usar a função plot para desenhar no gráfico o valor da variável b em cada BAR da sequência de tempo, em linha ◦
Será que nós pensamos que se houver um solenoide BAR, b continuará acumulando 1? Claro que não, aqui nós não usamos nenhuma palavra-chave para declarar a variável b, quando a inicialização é 0.b=0
E isso é executado em cada BAR, então você pode ver que o resultado de executar este código é que a variável b é redefinida para 0 a cada vez que a variável a é verdadeira, então isso corresponde aclose > open
Então, nesta rodada de execução do código, b é adicionado 1, quando a função de plot é 1, mas na próxima rodada de execução do código, b é re-atribuído a 0.
Quando falamos de operadores de atribuição, temos que estender a explicação a duas palavras-chave:var
、varip
Na verdade, essa palavra-chave, que já vimos e usamos em tutoriais anteriores, só que não foi explorada em detalhes.
var é uma palavra-chave usada para alocar e inicializar variáveis de uma só vez. Normalmente, a sintaxe de atribuição de variáveis que não contém a palavra-chave var leva a que os valores das variáveis sejam cobertos sempre que os dados são atualizados. Por outro lado, quando as variáveis de alocamento são usadas com a palavra-chave var, elas podem ser mantidas em um estado semelhante, mesmo que os dados sejam atualizados.
Nós ainda usamos esse exemplo, mas nós usamos para atribuir um valor a bvar
Palavras-chave:
a = close > open
var b = 0
if a
b := b + 1
plot(b)
var
A palavra-chave permite que a variável b execute apenas a primeira atribuição inicial, sem que a lógica da estratégia de execução de cada vez que b seja redefinida para 0, de modo que a linha desenhada no tempo de execução pode ser observada para obter b, ou seja, o número de BARs de linha de onda que ocorreram quando o atual K BAR foi medido.
As variáveis de uma declaração var podem ser escritas não apenas em escala global, mas também em blocos de código, como neste exemplo:
strategy(overlay=true)
var a = close
var b = 0.0
var c = 0.0
var green_bars_count = 0
if close > open
var x = close
b := x
green_bars_count := green_bars_count + 1
if green_bars_count >= 10
var y = close
c := y
plot(a, title = "a")
plot(b, title = "b")
plot(c, title = "c")
A variável ‘a’ mantém o preço de fechamento da primeira linha da série. A variável ‘b’ mantém o preço de fechamento da primeira barra de preço de alumínio verde da série. A variável ‘c’ mantém o preço de fechamento da décima chiclete verde da série.
varip
A primeira vez que vimos a palavra-chave, podemos ver a descrição da palavra-chave:
varip ((var intrabar persist) é uma palavra-chave usada para a distribuição e inicialização de variáveis de uma só vez. É semelhante à palavra-chave var, mas a variável que usa a declaração varip mantém seu valor entre as atualizações de linha K em tempo real.
Não é difícil de entender, mas é fácil de entender com um exemplo.
strategy(overlay=true)
// 测试 var varip
var i = 0
varip ii = 0
// 将策略逻辑每轮改变的i、ii打印在图上
plotchar(true, title="ii", char=str.tostring(ii), location=location.abovebar, color=color.red)
plotchar(true, title="i", char=str.tostring(i), location=location.belowbar, color=color.green)
// 每轮逻辑执行都给i、ii递增1
i := i + 1
ii := ii + 1
Este código de teste funciona de forma diferente em modelos de preços de fechamento e modelos de preços em tempo real:
Modelos de preços em tempo real:
Lembram-se de quando nós dissemos que a estratégia era executada em um período de BAR histórico e um período de BAR em tempo real?var
、varip
Variáveis declaradasi
、ii
Cada vez que o código da estratégia é executado, uma operação de incremento é executada. Assim, é possível ver que os números exibidos na linha KBAR do resultado da retomada são incrementados um por um. Quando a fase histórica da linha K termina, começa a fase de linha K em tempo real. As variáveis das declarações var e varip começam a mudar.i := i + 1
eii := ii + 1
A diferença é que ii é modificado a cada vez. Embora i seja modificado a cada vez, a próxima rodada de execução da lógica da estratégia retorna ao valor anterior (lembre-se do mecanismo de rolagem que explicamos no capítulo anterior “Execução do modelo”?), até que o atual KBAR seja executado e o valor de i seja atualizado (ou seja, a próxima rodada de execução da lógica da estratégia não retorna ao valor anterior). Portanto, pode-se ver que a variável i ainda é aumentada a cada BAR.1.
Modelo de fechamento: Como o modelo de preço de fechamento executa uma lógica de estratégia para cada linha K BAR. Assim, no modelo de preço de fechamento, a fase de linha K histórica e a fase de linha K em tempo real, as variáveis das declarações var, varp apresentam um desempenho excessivo perfeitamente consistente no exemplo acima, aumentando 1 para cada linha K BAR.
Operador | ilustrar |
---|---|
+ | Adição |
- | Subtração |
* | Multiplicação |
/ | Eliminação |
% | Buscar exemplos |
+
、-
Um operador pode ser usado como um operador binário ou como um operador unitário. Outros operadores aritméticos só podem ser usados como um operador binário.
1 , o operador de aritmética é de ambos os lados do tipo de valor, o resultado é o tipo de valor, inteiro ou número de ponto flutuante, dependendo do resultado da operação.
2. Se um número de operações é uma string, o operador é+
, o resultado é uma string, o valor é convertido em forma de string, e depois as strings são empilhadas. Se for outro operador de aritmética, tentaremos converter a string em um valor, e depois operar.
3. Se um dos números de operação for na, o resultado será nulo, mostrando NaN quando impresso no FMZ.
a = 1 + 1
b = 1 + 1.1
c = 1 + "1.1"
d = "1" + "1.1"
e = 1 + na
runtime.log("a:", a, ", b:", b, ", c:", c, ", d:", d, ", e:", e)
// a: 2 , b: 2.1 , c: 11.1 , d: 11.1 , e: NaN
A linguagem Pine no FMZ é um pouco diferente da linguagem Pine no Trading View, a linguagem Pine no FMZ não é muito exigente quanto aos requisitos de tipo de variável. Por exemplo:
a = 1 * "1.1"
b = "1" / "1.1"
c = 5 % "A"
plot(a)
plot(b)
plot(c)
Pode ser executado no FMZ, mas será reportado um erro de tipo no trading view. Para um operador de aritmética, quando os números de operação de ambos os lados são strings, o sistema irá converter a string em um valor numérico e depois calcular. Se uma string não-numérica não puder ser calculada, o resultado da operação do sistema será um valor nulo na.
Os operadores de comparação são binários.
Operador | ilustrar |
---|---|
< | Menos de |
> | Maior do que |
<= | Menos que igual a |
>= | Maior do que igual a |
== | Equivalência |
!= | Desigualdade |
Exemplo de teste:
a = 1 > 2
b = 1 < 2
c = "1" <= 2
d = "1" >= 2
e = 1 == 1
f = 2 != 1
g = open > close
h = na > 1
i = 1 > na
runtime.log("a:", a, ", b:", b, ", c:", c, ", d:", d, ", e:", e, ", f:", f, ", g:", g, ", h:", h, ", i:", i)
// a: false , b: true , c: true , d: false , e: true , f: true , g: false , h: false , i: false
Como você pode ver, o operador de comparação é muito simples de usar, mas é o operador que mais usamos quando escrevemos estratégias. Você pode comparar valores, mas também pode comparar variáveis internas, comoclose
、open
espere.
Como um operador de cálculo, o FMZ é diferente do Pine no Trading View, o FMZ não tem um tipo de requisição particularmente rigoroso, então declarações como essad = "1" >= 2
No FMZ, não há erro, a execução é feita primeiro com a conversão da string para um valor numérico e depois a operação de comparação. No Trading View, há erro.
Operador | Código de identificação | ilustrar |
---|---|---|
Não. | not | Operador unitário, não operativo |
e | and | Operador binário, com () e () |
ou | or | Operador binário, ou operação |
Quando falamos de operadores lógicos, temos que falar de tabelas de valores reais. Tal como aprendemos quando estávamos no ensino médio, só que aqui estamos testando e aprendendo no sistema de feedback:
a = 1 == 1 // 使用比较运算符构成的表达式,结果为布尔值
b = 1 != 1
c = not b // 逻辑非操作符
d = not a // 逻辑非操作符
runtime.log("测试逻辑操作符:and", "#FF0000")
runtime.log("a:", a, ", c:", c, ", a and c:", a and c)
runtime.log("a:", a, ", b:", b, ", a and b:", a and b)
runtime.log("b:", b, ", c:", c, ", b and c:", b and c)
runtime.log("d:", d, ", b:", b, ", d and b:", d and b)
runtime.log("测试逻辑操作符:or", "#FF0000")
runtime.log("a:", a, ", c:", c, ", a or c:", a or c)
runtime.log("a:", a, ", b:", b, ", a or b:", a or b)
runtime.log("b:", b, ", c:", c, ", b or c:", b or c)
runtime.log("d:", d, ", b:", b, ", d or b:", d or b)
runtime.error("stop")
Para evitar que o sistema de rastreamento fosse influenciado pela impressão contínua de informações, usamosruntime.error("stop")
A frase é executada uma vez que a impressão é executada, e o erro anormal é lançado para que a detecção seja interrompida. Depois, você pode observar a informação de saída e descobrir que o conteúdo da impressão e a tabela de valores reais são na verdade os mesmos.
Utilização do operador triangular? :
Expressões trigonométricas combinadas com números operacionaiscondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
Nós já vimos isso nos cursos anteriores. O que chamamos de expressão triangular, um operador triangular significa que há um total de três operações.
condition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
O que está acontecendo?condition
É um critério de julgamento, se o valor da expressão de verdade for:valueWhenConditionIsTrue
Secondition
O valor da expressão para o caso évalueWhenConditionIsFalse
。
O blogueiro, que não tem nenhuma utilidade prática, mas é fácil de demonstrar:
a = close > open
b = a ? "阳线" : "阴线"
c = not a ? "阴线" : "阳线"
plotchar(a, location=location.abovebar, color=color.red, char=b, overlay=true)
plotchar(not a, location=location.belowbar, color=color.green, char=c, overlay=true)
A expressão triangular também pode ser embutida, como fizemos no tutorial anterior.
a = close > open
b = a ? math.abs(close-open) > 30 ? "阳线" : "十字星" : math.abs(close-open) > 30 ? "阴线" : "十字星"
c = not a ? math.abs(close-open) > 30 ? "阴线" : "十字星" : math.abs(close-open) > 30 ? "阳线" : "十字星"
plotchar(a, location=location.abovebar, color=color.red, char=b, overlay=true)
plotchar(not a, location=location.belowbar, color=color.green, char=c, overlay=true)
Isso é o equivalente acondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
EmvalueWhenConditionIsTrue
、valueWhenConditionIsFalse
Em vez disso, usamos outras expressões tridimensionais.
Utilização do operador Histórico[]
, referindo-se aos valores históricos na sequência de tempo. Estes valores históricos são os valores da variável na linha K BAR anterior à linha K BAR atual no tempo de execução do script.[]
O operador é usado para chamadas de variáveis, expressões e funções.[]
O valor entre parênteses é o desvio do histórico que queremos citar do BAR da linha K atual. Por exemplo, se eu quiser citar o preço de fechamento de uma linha K BAR anterior, escrevo:close[1]
。
A forma de escrever a palavra é a mesma que a forma de escrever a palavra em português.
high[10]
ta.sma(close, 10)[1]
ta.highest(high, 10)[20]
close > nz(close[1], open)
[]
O operador só pode ser usado uma vez no mesmo valor, então isso é errado, e vai falhar:
a = close[1][2] // 错误
Talvez você veja aqui, alguns colegas de aula dizem que os operadores[]
E o problema é que o que é usado para construções de séries é muito parecido com o que é usado para construções de séries.
Em seguida, vamos usar um exemplo para ilustrar a diferença entre uma série (series) e um conjunto (array) na linguagem Pine.
strategy("test", overlay=true)
a = close
b = close[1]
c = b[1]
plot(a, title="a")
plot(b, title="b")
plot(c, title="c")
Embora dizendoa = close[1][2]
O blogueiro também escreve sobre o assunto:
b = close[1]
c = b[1]
A partir daí, a sequência de números, que é a sequência de números, não é um erro, se entendermos a sequência de números como uma sequência normal.b = close[1]
Depois de atribuir um valor, b deve ser um número, masc = b[1]
, b ainda pode ser novamente usado para usar o operador de referência histórico. Como pode ser visto na linguagem Pine, o conceito de série não é tão simples quanto o de arquivos. Pode ser entendido c