[TOC] ¿Qué quieres decir?
Tutorial de video de apoyo:https://www.youtube.com/watch?v=CA3SwJQb_1g
FMZ Quant Trading Platform admite la escritura de estrategias de lenguaje Pine, backtesting y trading en vivo de estrategias de lenguaje Pine, y es compatible con versiones más bajas de lenguaje Pine.Plaza Estrategiaen la plataforma de negociación cuantitativa FMZ (FMZ.COM).
FMZ admite no solo el lenguaje Pine, sino también la poderosa función de dibujo del lenguaje Pine. Las diversas funciones, herramientas ricas y prácticas, gestión eficiente y conveniente en la plataforma FMZ mejoran aún más la viabilidad de la estrategia Pine (script). Basándose en la compatibilidad con el lenguaje Pine, FMZ también amplía, optimiza y recorta el lenguaje Pine hasta cierto punto. Antes de ingresar al tutorial oficialmente, echemos un vistazo a los cambios realizados en el lenguaje Pine en FMZ en comparación con la versión original.
Un breve resumen de algunas de las diferencias obvias:
//@version
y elstrategy
, indicator
las declaraciones al comienzo del código no son obligatorias de escribir, FMZ no admiteimport
para importarlibrary
Funciona por ahora.Se puede ver que algunas estrategias escritas así:
//@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)
O escribe así:
//@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)
En FMZ se puede simplificar a:
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)
O también:
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)
Modelo de precios de cierre y modelo de precios en tiempo real
En la vista de comercio, podemos utilizar elcalc_on_every_tick
Parámetro delstrategy
función para establecer el guión de la estrategia para ejecutar la lógica de la estrategia en tiempo real cuando el precio cambia cada vez.calc_on_every_tick
el parámetro debe estar establecido entrue
El.calc_on_every_tick
el parámetro predeterminado esfalse
, es decir, la lógica de la estrategia se ejecuta solo cuando la BAR de la línea K actual de la estrategia se completa por completo.
En FMZ, se establece por los parámetros de la plantilla
Control de precisión numérica, como el precio y el importe de la orden cuando se ejecuta la estrategia debe especificarse en FMZ En la vista comercial, no hay ningún problema de precisión al colocar órdenes comerciales reales, porque solo se puede probar en simulación. En FMZ, es posible ejecutar la estrategia Pine en el comercio real. Luego, la estrategia debe ser capaz de especificar la precisión del precio y la precisión del monto del pedido de la variedad comercial de manera flexible. La configuración de precisión controla el número de decimales en los datos relevantes para evitar que los datos no cumplan con los requisitos de orden del intercambio y, por lo tanto, no puedan realizar un pedido.
Código del contrato de futuros
Si el producto de negociación en FMZ es un contrato, tiene dos atributos, son swap
Por ejemplo, algunas bolsas tienen contratos trimestrales, puede rellenar el código de contrato en el siguiente orden:quarter
Estos códigos de contrato son consistentes con los códigos de contrato de futuros definidos en el documento de la API del lenguaje Javascript/python/c++ de FMZ.
Para otros ajustes, como el importe mínimo de la orden, el importe de la orden por defecto, etc., consulte la introducción del parámetro en
runtime.debug
, runtime.log
, runtime.error
se utiliza para depurar.Se han añadido 3 funciones a la plataforma FMZ para la depuración.
runtime.debug
: Imprimir información de variables en la consola, que generalmente no se utiliza con esta función.
runtime.log
Funciones específicas para el idioma PINE en FMZ.
runtime.log(1, 2, 3, close, high, ...), Multiple parameters can be passed.
runtime.error
: Resultará en un error de ejecución con el mensaje de error especificado en el parámetro de mensaje cuando se llame.
runtime.error(message)
overlay
Parámetro se extiende en algunas de las funciones de dibujoEn el lenguaje Pine en FMZ, las funciones de dibujoplot
, plotshape
, plotchar
, etc. han añadido eloverlay
apoyo de parámetros, que permita especificar el dibujo del gráfico principal o del subgráfico.overlay
está configurado para:true
para dibujar en el gráfico principal, yfalse
se establece para utilizar el subgráfico, lo que permite a la estrategia Pine en FMZ dibujar el gráfico principal y el subgráfico al mismo tiempo.
syminfo.mintick
Variable incorporadaLa variable incorporada desyminfo.mintick
se define como el valor mínimo de tick para el símbolo actual. Este valor puede ser controlado por el parámetro modelo de precios de precisión de la moneda en la syminfo.mintick
es 0,01.
Por ejemplo: el precio del pedido es de 8000, la dirección de venta, la cantidad es de 1 lote (pieza, hoja), el precio medio después de la transacción no es de 8000, sino inferior a 8000 (el coste incluye la tasa de manipulación).
Al comenzar a aprender los conceptos básicos del lenguaje Pine, puede haber algunos ejemplos de instrucciones y gramática de código con los que no estamos familiarizados. No importa si no lo entiendes, primero podemos familiarizarnos con los conceptos y entender el propósito de la prueba, o puedes consultar la documentación del lenguaje Pine en FMZ para obtener instrucciones. Luego sigue el tutorial paso a paso para familiarizarte con varias gramáticas, instrucciones, funciones y variables incorporadas.
Al comenzar a aprender el lenguaje Pine, es muy necesario entender los conceptos relacionados, como el proceso de ejecución del programa de script del lenguaje Pine. La estrategia del lenguaje Pine se ejecuta sobre la base del gráfico. Se puede entender que la estrategia del lenguaje Pine es una serie de cálculos y operaciones, que se ejecutan en el gráfico en el orden de las series de tiempo a partir de los primeros datos que se han cargado en el gráfico. La cantidad de datos que el gráfico carga inicialmente es limitada. En el comercio real, la cantidad máxima de datos generalmente se determina en función del volumen máximo de datos devueltos por la interfaz de intercambio, y la cantidad máxima de datos durante la prueba posterior se determina en función de los datos proporcionados por la fuente de datos del sistema de backtesting. La barra de K-line más a la izquierda en el gráfico, es decir, el primer conjunto de datos del gráfico, tiene un valor de índice de 0.bar_index
en el lenguaje Pine.
plot(bar_index, "bar_index")
Elplot
la función es una de las funciones que vamos a utilizar más en el futuro. el uso es muy simple, es dibujar una línea en el gráfico de acuerdo con los parámetros de entrada, los datos de entrada esbar_index
, y la línea se llamabar_index
. Se puede ver que el valor de la línea llamada bar_index en la primera barra es 0, y aumenta en 1 a la derecha a medida que aumenta la barra.
Debido a que las configuraciones de la estrategia son diferentes, los métodos de ejecución del modelo de la estrategia son diferentes, se pueden dividir enclosing price model
yreal-time price model
También hemos introducido brevemente los conceptos de ellos antes.
Modelo de precios de cierre
Cuando el código de estrategia se ejecuta, el período de la barra de la línea K actual se ejecuta completamente, y cuando la línea K se cierra, el período de la línea K se ha completado.
Modelo de precios en tiempo real
Cuando se ejecuta el código de estrategia, independientemente de si la barra de la línea K actual está cerrada o no, la lógica de la estrategia Pine se ejecutará cuando el mercado cambie cada vez, y la señal de negociación activada se ejecutará inmediatamente.
Cuando la estrategia del lenguaje Pine se ejecuta de izquierda a derecha en el gráfico, las barras de la línea K en el gráfico se dividen enHistorical Bars
yReal-time Bars
:
Bar histórico
Cuando la estrategia está configurada en Historical Bars
. La lógica de la estrategia se ejecuta sólo una vez en cadahistorical bar
¿ Qué pasa?
Cuando la estrategia se establece en historical bars
. La lógica de la estrategia se ejecuta sólo una vez en cadahistorical bar
.
Cálculo basado en bares históricos: El código de estrategia se ejecuta una vez en el estado de cierre de la barra histórica, y luego el código de estrategia continúa ejecutándose en la siguiente barra histórica hasta que todas las barras históricas se ejecutan una vez.
Bar en tiempo real
Cuando la estrategia se ejecuta hasta la última barra de la línea K en el extremo derecho, la barra es una barra en tiempo real.
Cuando la estrategia se establece en
Cálculo basado en Bar en tiempo real:
Si la estrategia está configurada en high
, low
, close
Los valores de los valores de mercado se determinan en barras históricas, y estos valores pueden cambiar cada vez que el mercado cambia en barras en tiempo real. Por lo tanto, los datos como los indicadores calculados en base a estos valores también cambiarán en tiempo real.close
siempre representa el último precio actual, yhigh
ylow
siempre representan el punto más alto y el punto más bajo alcanzado desde el inicio de la barra actual en tiempo real. Estas variables integradas representan el valor final de la barra en tiempo real cuando se actualizó por última vez.
Mecanismo de retroceso cuando se ejecutan estrategias en tiempo real Bar (modelo de precios en tiempo real): Durante la ejecución de Bar en tiempo real, el restablecimiento de variables definidas por el usuario antes de cada nueva iteración de la estrategia se llama rollback.
Atención:
/*backtest
...
..
.
*/
El contenido del paquete es la información de configuración de backtest guardada en forma de código en la 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("before n + 1, n:", n, " current bar_index:", bar_index)
n := n + 1
runtime.log("after n + 1, n:", n, " current bar_index:", bar_index)
plot(n, title="n")
Sólo examinamos la escena ejecutada durante el tiempo real bares, por lo que utilizamos elnot barstate.ishistory
expresión para limitar la acumulación de la variable n sólo en el tiempo real Bar, y el usoruntime.log
Función para obtener la información en el registro de estrategia antes y después de la operación de acumulación.plot
, se puede ver que n es siempre 0 cuando la estrategia se está ejecutando en Bares históricos. Cuando se ejecuta la Bar en tiempo real, se activa la operación de sumar 1 a n, y la operación de sumar 1 a n se ejecuta cuando la estrategia se ejecuta en cada ronda de la Bar en tiempo real. Se puede observar a partir del mensaje de registro que n se restablecerá al valor finalmente enviado por la estrategia de ejecución de Bar anterior cuando el código de estrategia se ejecute nuevamente en cada ronda. La actualización del valor de n se enviará cuando el código de estrategia se ejecute en la Bar en tiempo real por última vez, por lo que puede ver que el valor de la curva n aumenta en 1 con cada aumento de Bar a partir de la Bar en tiempo real en el gráfico.
Resumen:
Debido al retroceso de los datos, las operaciones de dibujo, como las curvas en el gráfico también pueden causar rediseño.
var n = 0
if not barstate.ishistory
runtime.log("before n + 1, n:", n, " current bar_index:", bar_index)
n := open > close ? n + 1 : n
runtime.log("after n + 1, n:", n, " current bar_index:", bar_index)
plot(n, title="n")
Captura de pantalla del tiempo A
Captura de pantalla del tiempo B
Sólo modificamos la frase:n := open > close ? n + 1 : n
, sólo se añade 1 a n cuando la barra actual en tiempo real es una línea negativa (es decir, el precio de apertura es mayor que el precio de cierre). Se puede ver que en el primer gráfico (tiempo A), ya que el precio de apertura era mayor que el precio de cierre (línea negativa) en ese momento, n se acumuló en 1, y el valor de n mostrado en la curva del gráfico fue 5. Luego el mercado cambió y el precio se actualizó como se muestra en el segundo gráfico (tiempo B). En este momento, el precio de apertura es menor que el precio de cierre (línea positiva), y el valor de n retrocede sin incrementar en 1. La curva de n en el gráfico también se vuelve a dibujar inmediatamente, y el valor de n en la curva es 4. Por lo tanto, las señales, como el cruce y las mostradas en las barras en tiempo real, son inciertas y pueden cambiar.
Contexto variable en las funciones
De acuerdo con algunas descripciones en tutoriales de Pine, las variables de la función tienen las siguientes diferencias con las variables fuera de la función:
El historial de las variables de serie utilizadas en la función Pine se crea con cada llamada sucesiva a la función. Si la función no se llama en cada barra en la que se ejecuta el script, esto resultará en una discrepancia entre los valores históricos de la serie dentro y fuera del bloque local de la función. Por lo tanto, si la función no se llama en cada barra, la serie referenciada dentro y fuera de la función con el mismo valor de índice no se referirá al mismo punto histórico.
No importa, lo resolveremos con un código de prueba que se ejecuta en 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 pantalla de la ejecución de la prueba de retroceso
El código de prueba es relativamente simple, principalmente para examinar los datos a los que se hace referencia mediante dos métodos, a saber:f(a) => a[1]
yf2() => close[1]
.
f(a) => a[1]
: Utilice el método de transmisión de parámetros, la función regresa aa[1]
finally.
f2() => close[1]
: Utilice la variable incorporadaclose
directamente, y la función vuelve aclose[1]
finally.
El[]
El símbolo se utiliza para referirse al valor histórico de la variable de la serie de datos, y el cierre[1] se refiere a los datos del precio de cierre en la barra antes del precio de cierre actual.
plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A")
Dibuja un carácter f(close)
.
plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
Dibuja un carácter f2()
.
plot(close[2], title = "close[2]", color = color.red, overlay = true)
Dibuje una línea, el color es rojo, y la posición dibujada (en el eje Y) es:close[2]
, que es el precio de cierre de la segunda barra antes de la barra actual (contando 2 barras a la izquierda).
plot(close[1], title = "close[1]", color = color.green, overlay = true)
Dibuje una línea, el color es verde, y la posición dibujada (en el eje Y) es:close[1]
, que es el precio de cierre de la primera barra antes de la barra actual (contando 1 barra a la izquierda).
Se puede ver desde la captura de pantalla de la estrategia backtesting que aunque tanto la funciónf(a) => a[1]
utilizado para dibujar el marcador A y la funciónf2() => close[1]
La posición del marcador plot(close[2], title = "close[2]", color = color.red, overlay = true)
, los datos utilizados para trazar la línea esclose[2]
.
La razón es calcular si dibujar los marcadores bar_index
Los marcadores f(a) => a[1]
no será el mismo valor al que hace referencia la funciónf2() => close[1]
si la función no se llama en cada Bar (incluso si ambos utilizan el mismo índice como [1]).
Algunas funciones integradas deben calcularse en cada barra para calcular sus resultados correctamente
Para ilustrar esta situación con un ejemplo simple:
res = close > close[1] ? ta.barssince(close < close[1]) : -1
plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)
Escribimos el código de llamada de la funciónta.barssince(close < close[1])
en un operador ternariocondition ? value1 : value2
Esto hace que la función ta.barssince se llame sólo cuandoclose > close[1]
Pero elta.barssince
La función es calcular el número de K-líneas desde la última vezclose < close[1]
Cuando se llama la función ta.barssince, siempre es close > close[1], es decir, el precio de cierre actual es mayor que el precio de cierre de la barra anterior. Cuando se llama la función ta.barssince, la condición close < close [1] no se establece, y no hay una posición reciente donde se mantenga.
ta.barssince: Cuando se llama, la función devuelve na si la condición nunca se ha cumplido antes de la línea K actual.
Como se muestra en el cuadro:
Así que cuando el gráfico se dibuja, sólo los datos con un valor para la variable res (-1) se dibuja.
Para evitar este problema, simplemente tomamos elta.barssince(close < close[1])
La función llama al operador ternario y lo escribe fuera de cualquier posible rama condicional, haciendo que realice cálculos en cada K-line 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)
El concepto de serie de tiempo es muy importante en el lenguaje Pine, y es un concepto que debemos entender cuando aprendemos el lenguaje Pine. La serie de tiempo no es un tipo sino una estructura básica para almacenar valores continuos de variables a lo largo del tiempo. Sabemos que los scripts de Pine se basan en gráficos, y el contenido más básico que se muestra en el gráfico es el gráfico de líneas K. Serie de tiempo donde cada valor está asociado con una marca de tiempo de una barra de líneas K.open
es una variable incorporada (integrada) del lenguaje Pine, y su estructura es almacenar la serie de tiempo del precio de apertura de cada K-line Bar.open
representa los precios de apertura de todas las barras de la línea K desde la primera barra al comienzo del gráfico de la línea K actual hasta la barra donde se ejecuta el script actual. Si el gráfico de la línea K actual es un período de 5 minutos, cuando cotizamos (o usamos)open
En el código de la estrategia de Pine, es el precio de apertura de la barra de la línea K cuando el código de la estrategia se ejecuta actualmente.[]
Cuando la estrategia Pine se ejecuta en una determinada K-line Bar, utilizaropen[1]
para referirse al precio de apertura de la barra anterior de la línea K (es decir, el precio de apertura del período anterior de la línea K) que hace referencia a laopen
serie de tiempo en la que esta barra de línea K está siendo ejecutada actualmente por el script.
Las variables en series de tiempo son muy convenientes para la computación
Tomemos la función incorporadata.cum
Por ejemplo:
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 ensayo:
v1 = 1
v2 = ta.cum(v1)
plot(v1, title="v1")
plot(v2, title="v2")
plot(bar_index+1, title="bar_index")
Hay muchas funciones incorporadas comota.cum
que puede procesar datos sobre series temporales directamente.ta.cum
es la acumulación de los valores correspondientes a las variables pasadas en cada K-línea Bar, y a continuación, usamos un gráfico para que sea más fácil de entender.
Proceso de operación de la estrategia | Variable incorporada bar_index | V1 | V2 |
---|---|---|---|
La estrategia se ejecuta en la primera barra de la línea K. | 0 | 1 | 1 |
La estrategia se ejecuta en la segunda barra de la línea K. | 1 | 1 | 2 |
La estrategia se ejecuta en la tercera barra de la línea K. | 2 | 1 | 3 |
… | … | … | … |
La estrategia se ejecuta en la barra de la línea K N + 1 | No | 1 | N + 1 |
Se puede ver que v1, v2 e incluso bar_index son todas estructuras de series temporales, y hay datos correspondientes en cada barra.
Porque la variable v1 es 1 en cada Bar, cuando elta.cum(v1)
La función se ejecuta en la primera K-línea Bar, sólo hay la primera Bar, por lo que el resultado del cálculo es 1 y asignado a la variable v2.
¿Cuándo?ta.cum(v1)
Si el resultado de cálculo es 2, que se asigna a la variable v2, y así sucesivamente. De hecho, se puede observar que v2 es el número de barras de línea K en el gráfico, ya que el índice de la línea Kbar_index
se incrementa desde 0, entoncesbar_index + 1
En el gráfico, también podemos ver que las líneasv2
ybar_index
de hecho se superponen.
De la misma manera, también puedo utilizar elta.cum
la función incorporada para calcular la suma de los precios de cierre para todas las barras en el gráfico actual. todo lo que tengo que hacer es escribirlo así:ta.cum(close)
, Cuando la estrategia se ejecuta a la barra en tiempo real en el extremo derecho, el resultado calculado porta.cum(close)
es la suma de los precios de cierre de todas las barras en el gráfico (si no corre hacia la extrema derecha, solo se acumula hasta la barra actual).
Las variables de las series temporales también se pueden calcular utilizando operadores, como el código:ta.sma(high - low, 14)
, restar la variable incorporadahigh
(el precio más alto de la barra de la línea K) desdelow
(el precio más bajo de K-line Bar), y finalmente utilizar elta.sma
función para calcular el valor medio.
El resultado de una llamada de función también dejará rastros de valores en la serie de tiempo.
v1 = ta.highest(high, 10)[1]
v2 = ta.highest(high[1], 10)
plot(v1, title="v1", overlay=true)
plot(v2, title="v2", overlay=true)
El código de prueba se ejecuta durante el backtesting, y se puede observar que los valores dev1
yv2
El resultado calculado por la llamada de la función dejará rastros del valor en la serie de tiempo, como elta.highest(high, 10)
en el códigota.highest(high, 10)[1]
El resultado calculado por la llamada de la función también puede utilizar [1] para referirse a su valor histórico.ta.highest(high, 10)
correspondiente a la barra anterior de la barra actual, el resultado del cálculo esta.highest(high[1], 10)
Así que...ta.highest(high[1], 10)
yta.highest(high, 10)[1]
son exactamente equivalentes.
Utilice otra función de dibujo para obtener la información de verificación:
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)
Podemos ver que los valores de la variable a y la variable b en la serie de tiempo se muestran por encima y por debajo de las barras correspondientes. Podemos mantener este código de dibujo durante el proceso de aprendizaje, porque a menudo es posible que necesitemos obtener información en la tabla para su observación durante las pruebas y la experimentación.
En la parte inicial del tutorial, hemos resumido algunas diferencias en el uso del lenguaje Pine en FMZ y Trading View.indicator()
, strategy()
, ylibrary()
Por supuesto, con el fin de ser compatible con versiones anteriores de guiones Pine, estrategias tales como://@version=5
, indicator()
, strategy()
Algunos ajustes de estrategia también se pueden establecer pasando parámetros en elstrategy()
function.
<version>
<declaration_statement>
<code>
El<version>
La información de control de versiones puede omitirse.
El lenguaje del pino utiliza//
como un símbolo de comentario de una sola línea, ya que el lenguaje Pine no tiene un símbolo de comentario de varias líneas. FMZ extiende el símbolo de comentario/**/
para las observaciones de varias líneas.
Las líneas en el script que no son comentarios o directivas del compilador son instrucciones, que implementan el algoritmo del script.
if
, for
, while
o bienswitch
estructuraLas declaraciones pueden organizarse de varias maneras.
space
Las líneas que comienzan en la primera posición, por definición, se convierten en parte del alcance global del script.local block
Un bloque local debe estar recubierto por una pestaña o cuatro espacios (de lo contrario, se analizará como el código concatenado de la línea anterior, es decir, se juzgará que es el contenido continuo de la línea anterior de código), y cada bloque local define un alcance local diferente.Por ejemplo, incluye tres bloques locales, uno en la declaración de función personalizada y dos en la declaración de variable utilizando la estructura if, de la siguiente manera:
indicator("", "", true) // declaration statement (global scope), can be omitted
barIsUp() => // function declaration (global scope)
close > open // local block (local scope)
plotColor = if barIsUp() // variable declaration (global scope)
color.green // local block (local scope)
else
color.red // local block (local scope)
runtime.log("color", color = plotColor) // Call a built-in function to output the log (global scope)
Las líneas largas se pueden dividir en varias líneas, o envueltas. Una línea envuelta debe ser recubierta por cualquier número de espacios, siempre que no sea un múltiplo de 4 (estos límites se utilizan para recubierto de bloques locales).
a = open + high + low + close
Se puede envuelven como (tenga en cuenta que el número de espacios recubiertos por línea no puede ser un múltiplo de 4):
a = open +
high +
low +
close
Una llamada de trama larga puede ser envuelta como:
close1 = request.security(syminfo.tickerid, "D", close) // syminfo.tickerid daily level closing price data series for the current trading pair
close2 = request.security(syminfo.tickerid, "240", close) // syminfo.tickerid 240-minute level closing price data series for the current trading pair
plot(ta.correlation(close, open, 100), // line-long plot() calls can be wrapped
color = color.new(color.purple, 40),
style = plot.style_area,
trackprice = true)
Sin embargo, dado que un bloque local debe comenzar con una hendidura en la gramática (4 espacios o 1 pestaña), al dividirlo en la siguiente línea, la continuación de una declaración debe comenzar con más de una hendidura (no igual a 4 múltiplos de espacios). Por ejemplo:
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 reconocer las variables, primero debemos entender el concepto de
(A-Z)
o en minúsculas(a-z)
letra o subrayado(_)
como el primer carácter del marcador.Por ejemplo, los siguientes marcadores denominados:
fmzVar
_fmzVar
fmz666Var
funcName
MAX_LEN
max_len
maxLen
3barsDown // Wrong naming! It used a numeric character as the leading character of the marker
Al igual que la mayoría de los lenguajes de programación, el lenguaje Pine también tiene sugerencias de escritura.
// name variables, constants
GREEN_COLOR = #4CAF50
MAX_LOOKBACK = 100
int fastLength = 7
// name functions
zeroOne(boolValue) => boolValue ? 1 : 0
Los operadores son algunos símbolos de operación utilizados en lenguajes de programación para construir expresiones, y las expresiones son reglas computacionales diseñadas para ciertos propósitos computacionales cuando escribimos estrategias.
Operadores de asignación, operadores aritméticos, operadores de comparación, operadores lógicos,? :
los operadores ternarios,[]
los operadores de referencia históricos.
Tomando el operador aritmético*
como ejemplo, es diferente del problema de tipo causado por el resultado de retorno del operador de lenguaje Pine en Trading View.
//@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)
Cuando se ejecuta este script en Trading View, se producirá un error de compilación.adjustedLength = lenInput * factor
, el resultado esseries int
tipo (serie), pero el segundo parámetro de la funciónta.ema
Pero no hay restricciones tan estrictas en FMZ, el código anterior puede ejecutarse normalmente.
Echemos un vistazo al uso de varios operadores juntos.
Hay 2 tipos de operadores de asignación:=
, :=
, que hemos visto en varios ejemplos en la parte inicial del tutorial.
El=
El operador se utiliza para asignar un valor a una variable cuando se inicializa o se declara.=
se iniciará con ese valor en cada barra siguiente. Estas son declaraciones de variables válidas:
a = close // Use built-in variables to assign values to a
b = 10000 // Use numerical assignment
c = "test" // Use string assignment
d = color.green // Use color value assignment
plot(a, title="a")
plot(b, title="b")
plotchar(true, title="c", char=str.tostring(c), color=d, overlay=true)
Tenga en cuenta que la declaración de asignacióna = close
, la variable a de cada barra es el precio de cierre (cierre) actual de la barra. Otras variablesb
, c
, d
se mantienen sin cambios y pueden probarse en el sistema de pruebas de retroceso en FMZ, y los resultados se pueden ver en el gráfico.
:=
Se utiliza para reasignar valores a las variables existentes.:=
El operador se utiliza para modificar los valores de las variables que han sido declaradas e inicializadas.
Si usamos el:=
operador para asignar un valor a una variable no inicializada o declarada, causará un error, por ejemplo:
a := 0
Por lo tanto, el:=
el operador de asignación se utiliza generalmente para reasignar variables existentes, por ejemplo:
a = close > open
b = 0
if a
b := b + 1
plot(b)
Juzgando siclose > open
(es decir, el BAR actual es una recta positiva), la variable a es verdad.b := b + 1
se ejecuta, y el operador de asignación:=
Entonces usamos la función gráfica para dibujar el valor de la variable b en cada BAR de la serie de tiempo en el gráfico, y conectarlos en una línea.
¿Creemos que cuando aparece una línea positiva BAR, b continuará acumulándose por 1? por supuesto que no, aquí declaramos e iniciamos la variable b como 0 sin usar ninguna designación de palabra clave.b=0
se ejecuta en cada BAR, por lo que podemos ver que el resultado de este código es restablecer la variable b a 0 cada vez, si la variable a es verdad, es decir, en línea conclose > open
, entonces b se incrementará en 1 cuando el código se ejecuta en esta ronda, y b es 1 cuando la función de gráfico dibuja, pero b se reasigna a 0 cuando el código se ejecuta en la siguiente ronda.
Cuando se trata de operadores de asignación, debemos ampliar en dos palabras clave:var
, varip
el var
De hecho, hemos visto y utilizado esta palabra clave en tutoriales anteriores, pero no la discutimos en detalle en ese momento.
var es una palabra clave utilizada para asignar y inicializar variables de una sola vez. En general, la gramática de asignación de variables que no contiene la palabra clave var hace que el valor de la variable se sobrescriba cada vez que se actualizan los datos.
Todavía usamos este ejemplo, pero usamos elvar
palabra clave al asignar un valor a b aquí.
a = close > open
var b = 0
if a
b := b + 1
plot(b)
Elvar
palabra clave permite que la variable b para realizar la asignación inicial sólo, y luego no se restablecerá b a 0 cada vez que se ejecuta la lógica de la estrategia, por lo que se puede observar a partir de la línea dibujada en tiempo de ejecución que b es el número de barras de la línea positiva que han aparecido cuando la línea actual K BAR fue backtested.
Las variables declaradas por var pueden escribirse no solo en el alcance global, sino también en bloques de código, como este ejemplo:
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")
La variable
variedad
Vemos la palabra clave.varip
Por primera vez, podemos ver la descripción de esta palabra clave:
varp (var intrabar persist) es una palabra clave para asignar e iniciar variables de una sola vez. Es similar a la palabra clave var, pero las variables declaradas con varp conservan sus valores cuando se actualizan en línea K en tiempo real.
¿Es difícil de entender? No importa, lo explicamos a través de un ejemplo, es fácil de entender.
strategy(overlay=true)
// test var varip
var i = 0
varip ii = 0
// Print the i and ii changed in each round of the strategy logic on the chart
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)
// Increment i and ii by 1 for each round of logic execution
i := i + 1
ii := ii + 1
Este código de prueba tiene diferentes prestaciones en el
Modelo de barra:
¿Recuerdan que la ejecución de la estrategia que explicamos anteriormente se divide en etapa histórica BAR y etapa BAR en tiempo real?i
, ii
declarado envar
, varip
Los números que se muestran en el K-line BAR del resultado de la prueba de retroceso se incrementan uno por uno. Cuando termina la etapa histórica de la línea K, comienza la etapa de la línea K en tiempo real. Las variables declaradas por var y varip comienzan a sufrir cambios diferentes.i := i + 1
yii := ii + 1
La diferencia es que ii se modifica cada vez. Aunque i se modifica cada vez, el valor anterior se restablecerá cuando se ejecute la lógica de estrategia en la siguiente ronda (recuerde el mecanismo de retroceso que explicamos en el capítulo anterior
Modelo de marca: Dado que el modelo Tick ejecuta la lógica de estrategia solo una vez por K-line BAR. Así que en el modelo de precio de cierre, las variables declaradas por var y varip se comportan exactamente igual en el ejemplo anterior incrementando en 1 para cada K-line BAR durante la etapa histórica de la línea K y la etapa de la línea K en tiempo real.
Operadores | Descripción |
---|---|
+ | Adición |
- | Sustracción |
* | Multiplicación |
/ | División |
% | Modulo |
El+
y-
Otros operadores aritméticos sólo se pueden utilizar como operadores binarios y se informará de un error si se utilizó como operadores unarios.
+
, el resultado del cálculo es una cadena, el valor se convertirá a la forma de cadena, y luego las cadenas se unen. Si es otro operador aritmético, tratará de convertir la cadena a un valor y luego llevar a cabo la operación.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
El lenguaje Pine en FMZ es un poco diferente del lenguaje Pine en Trading View, el lenguaje Pine en FMZ no es muy estricto sobre los tipos de variables.
a = 1 * "1.1"
b = "1" / "1.1"
c = 5 % "A"
plot(a)
plot(b)
plot(c)
Funciona en FMZ, pero reporta un error de tipo en la Vista de Comercio. Si ambos operandos del operador aritmético son cadenas, el sistema convierte las cadenas en valores numéricos y luego los calcula. Si una cadena no numérica no se puede calcular, el resultado de la operación del sistema es un valor nulo
Los operadores de comparación son todos operadores binarios.
Operadores | Descripción |
---|---|
< | < |
> | > |
<= | <= |
>= | >= |
== | == |
!= | != |
Ejemplo de ensayo:
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 podemos ver, el operador de comparación es muy simple de usar, pero también es el operador que más usamos al escribir estrategias.close
, open
, etc.
Al igual que con el operador, hay una diferencia sobre el lenguaje Pine entre FMZ y Trading View.d = "1" >= 2
no reportará un error en FMZ, y se ejecutará convirtiendo la cadena a un valor primero y luego comparando la operación. En Trading View, reportará un error.
Operadores | Símbolos de código | Descripción |
---|---|---|
No lo es | No lo es | Operador unario, no operaciones |
y | y | Operadores binarios y operaciones |
o bien | o bien | Operadores o operaciones binarias |
Cuando se trata de operadores lógicos, entonces debemos hablar de tablas de valores verdaderos. Lo mismo que aprendimos en la escuela secundaria, aquí sólo probamos y aprendemos en nuestro sistema de backtesting:
a = 1 == 1 // An expression formed by using comparison operators, the result is a Boolean value
b = 1 != 1
c = not b // Logical not operators
d = not a // Logical not operators
runtime.log("test the logical operator: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("test the logical operator: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")
Con el fin de no sobreimprimir mensajes, lanzamos un error con elruntime.error("stop")
Después de eso, podemos observar la información de salida, y podemos encontrar que el contenido impreso es en realidad el mismo que la tabla de valores reales.
Expresiones ternarias con el operador ternario? :
combinado con operandoscondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
También los hemos usado en las lecciones anteriores. la llamada expresión ternaria, operador ternario significa que hay tres operandos en él.
En elcondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
, condition
Si es verdadero, el valor de la expresión es:valueWhenConditionIsTrue
- Si es así.condition
es falso, entonces el valor de la expresión esvalueWhenConditionIsFalse
.
Ejemplo de una demostración conveniente, aunque de poca utilidad práctica:
a = close > open
b = a ? "positive line" : "negative line"
c = not a ? "negative line" : "positive line"
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)
¿Qué hacer si nos encontramos con un doji? ¡No importa! Expresiones ternales también se pueden anidar, como lo hicimos en el tutorial anterior.
a = close > open
b = a ? math.abs(close-open) > 30 ? "positive line" : "doji" : math.abs(close-open) > 30 ? "negative line" : "doji"
c = not a ? math.abs(close-open) > 30 ? "negative line" : "doji" : math.abs(close-open) > 30 ? "positive line" : "doji"
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)
De hecho, es equivalente a reemplazar a lavalueWhenConditionIsTrue
yvalueWhenConditionIsFalse
En elcondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
con otra expresión ternaria.
Utilice el operador histórico[]
para referirse a valores históricos en una serie de tiempo. Estos valores históricos son los valores de la variable en la barra de línea K antes de la barra de línea K actual cuando el script se estaba ejecutando.[]
El operador se utiliza después de las variables, expresiones y llamadas de funciones.[]
Los paréntesis cuadrados es el desplazamiento de los datos históricos que queremos hacer referencia de la actual K-línea BAR. Por ejemplo, si quiero citar el precio de cierre de la última K-línea BAR, lo escribimos como:close[1]
.
Hemos visto algo así en las lecciones anteriores:
high[10]
ta.sma(close, 10)[1]
ta.highest(high, 10)[20]
close > nz(close[1], open)
El[]
El operador sólo se puede utilizar una vez en el mismo valor, por lo que es incorrecto escribirlo así, y se reportará un error:
a = close[1][2] // error
Aquí, alguien puede decir que el operador[]
Se utiliza para la estructura de serie, parece que la estructura de serie (serie) es similar a la matriz!
Usemos un ejemplo para ilustrar la diferencia entre series y matrices en el lenguaje 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")
a = close[1][2]
informará de un error, pero:
b = close[1]
c = b[1]
Pero si se escribe por separado, no reportará un error. Si lo entendemos según la matriz habitual, después de la asignación deb = close [1]
, b debería ser un valor, peroc = b[1]
Se puede ver que el concepto de serie en el lenguaje Pine no es tan simple como una matriz. Se puede entender como el valor histórico en la última barra de cerrar (asignado a b), b también es una estructura de serie temporal (serie temporal), y su h