Type/to search
8
Follow
1364
Followers
Tutorial de introducción al lenguaje cuantitativo PINE de Inventor
Tutorials
Created 2022-05-30 16:23:43  Updated 2022-09-28 17:10:21
 0
 12336

Tutorial de introducción al lenguaje cuantitativo PINE de Inventor

El video tutorial también incluye:
¿Es muy difícil entrar en el comercio de cantidades? usando el trading view del lenguaje Pine desde el pequeño blanco hasta el gran dios Quant - el primer experto en el lenguaje Pine

La plataforma de comercio cuantitativo del inventor admite la estrategia de programación en el lenguaje Pine, admite la retroalimentación, las estrategias del lenguaje Pine en vivo, y es compatible con versiones más bajas del lenguaje Pine.Plaza de la estrategiaHay una gran cantidad de estrategias y scripts de Pine que han sido recopilados y trasladados.

FMZ no solo es compatible con el lenguaje Pine, sino también con la potente función de dibujo del lenguaje Pine. Las funciones de la plataforma FMZ, las herramientas prácticas y la administración eficiente y fácil, también mejoran aún más la utilidad de la estrategia y el guión de Pine. FMZ se basa en la compatibilidad con el lenguaje Pine, y al mismo tiempo se ha realizado un cierto grado de extensión, optimización y corte del lenguaje Pine.

En resumen, algunas de las diferencias más evidentes:

  • 1 Política de Pine en FMZ, identificación de la versión al comienzo del código//@versionY el código comienzastrategyindicatorLas frases no son obligatorias y FMZ no las soporta por el momento.importImportadolibraryfunción.

    Algunas de las estrategias que se pueden ver son las siguientes:

    pine
    //@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 lo que se puede leer es:

    pine
    //@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 la FMZ se puede simplificar como:

    pine
    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:

    pine
    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)
  • 2 , estrategia [script] Algunas configuraciones relacionadas con la transacción son establecidas por el parámetro "Pine Language Transaction Class Library" en la interfaz de estrategia FMZ.

    • Modelo de precios de cierre y modelo de precios en tiempo real
      En la vista comercial, podemos pasar porstrategyLa función decalc_on_every_tickParámetros para configurar la estrategia El script ejecuta la lógica de la estrategia en tiempo real cada vez que el precio cambia, en este momentocalc_on_every_tickLos parámetros se deben ajustar atruePor defectocalc_on_every_tickEl parámetro esfalseLa lógica de la estrategia se ejecuta cuando la línea K BAR actual de la estrategia se ha agotado completamente.
      En FMZ se puede configurar a través de los parámetros de la plantilla de la biblioteca de clases de intercambio de lenguaje Pine.

      img

    • La precisión de los valores como el precio, la cantidad de pedidos al momento de ejecutar la estrategia debe ser controlada en la FMZ
      En la vista de trading, ya que solo se puede hacer una prueba de simulación, no hay problemas de precisión de la hora de la orden en el mercado real. En FMZ, se puede ejecutar la estrategia de Pine en el mercado real. Entonces, se necesita una estrategia que pueda especificar con flexibilidad la precisión del precio de la variedad de transacciones y la precisión de la cantidad de pedidos.

    • Código del contrato a plazo
      La variedad de transacción en FMZ si es un contrato, tiene 2 propiedades: "pareja de transacción" y "código de contrato". Además de la necesidad de configurar claramente el par de transacción en el disco y en la retrospectiva, también se necesita un código de contrato específico configurado en el parámetro "código de variedad" de la plantilla de la biblioteca de transacciones del lenguaje Pine. Por ejemplo, los contratos de perpetuidad se rellenanswapEl código de contrato se puede especificar en función de si el intercambio en el que se opera tiene un contrato de este tipo. Por ejemplo, los contratos trimestrales de todos los intercambios se pueden completar aquí.quarterEstos códigos de contratos coinciden con los códigos de contratos futuros definidos en la documentación de la API de lenguaje Javascript/python/c++ de FMZ.

    Para otros ajustes, por ejemplo, la cantidad mínima de pedido, el número de pedido por defecto, etc., consulte la documentación en el idioma Pine.La base de datos de intercambio de la lengua PineIntroducción a los parámetros

  • 3、runtime.debugruntime.logruntime.errorFunción de extensión de FMZ para la delimitación de la función.

    En la plataforma FMZ se han añadido 3 funciones para la desinstalación.

    • runtime.debug: La función no se usa generalmente para imprimir información de variables en el control.

    • runtime.log: contenido de salida en el registro │ FMZ PINE tiene una función específica para el lenguaje │

      pine
      runtime.log(1, 2, 3, close, high, ...),可以传多个参数。
    • runtime.errorCuando se llama: se produce un error de ejecución y un mensaje de error como se indica en el parámetro message.

      pine
      runtime.error(message)
    1. parte de la función de dibujo se ha ampliadooverlayparámetro

    Funciones de dibujo en el lenguaje Pine en FMZplotplotshapeplotcharSe ha incrementadooverlayEl soporte de parámetros permite especificar el dibujo en el gráfico principal o en el gráfico secundario.overlayconfiguracióntruedibujado en el mapa principal, configurado comofalseDibujar en subdibujos. Permite que la estrategia Pine en FMZ se ejecute dibujando el gráfico principal y el gráfico secundario al mismo tiempo.

  • 5、syminfo.mintickValoración de las variables incorporadas

    syminfo.mintickLa variable interna se define como el valor de medida mínimo de la variedad actual. En la FMZOferta firme/Prueba retrospectivaEl parámetro de la plantilla Precisión de la moneda de precio en la interfaz de la biblioteca de clases de negociación del lenguaje Pine permite controlar este valor. La Precisión de la moneda de precio se establece en 2, es decir, el precio es preciso hasta el segundo dígito decimal en el momento de la negociación, y la unidad de cambio mínimo en el precio es de 0,01 .syminfo.mintickPor ejemplo, el valor de 0.01 ≠ 0.01 ≠ 0.01.

    1. El precio medio en FMZ PINE Script es el precio que incluye la comisión

    Por ejemplo: el precio de pedido es de 8000, la dirección de venta, la cantidad de 1 mano (un), el precio promedio después de la transacción no es de 8000, es inferior a 8000 (el costo incluye los honorarios).

Fundamentos de la lengua Pine

Al comenzar a aprender las bases del lenguaje Pine, es posible que no estemos familiarizados con las instrucciones y la gramática del código de algunos ejemplos. No importa si no entendemos, podemos familiarizarnos primero con los conceptos, comprender el propósito de la prueba o consultar la documentación del lenguaje Pine de FMZ para ver las instrucciones. Luego, siga el tutorial paso a paso para familiarizarse con la gramática, las instrucciones, las funciones y las variables integradas.

Ejecución del modelo

En la introducción al aprendizaje de la lengua Pine, es muy necesario conocer los conceptos relacionados con el proceso de ejecución de los programas de escritura en la lengua Pine. Las políticas de la lengua Pine se ejecutan en base a gráficos, que se pueden entender como una serie de cálculos y operaciones que se ejecutan en la tabla en orden cronológico, comenzando por los primeros datos que ya se han cargado en la tabla. La cantidad de datos cargados inicialmente en la tabla es limitada.bar_indexCita el índice de la línea K Bar en el momento de la ejecución de la secuencia de comandos Pine.

pine
plot(bar_index, "bar_index")

img

plotLa función es una de las que más usaremos en el futuro. Es muy sencillo de usar, es dibujar líneas en el gráfico de acuerdo a los parámetros introducidos, y los datos introducidos sonbar_indexLa línea se llamabar_indexSe puede ver que la línea llamada bar_index en la primera barra tiene un valor de 0 y aumenta a la derecha con el incremento de la barra.

La configuración de la política varía, y el modelo de ejecución de la política también varía.收盘价模型y实时价模型El concepto de modelo de precios de cierre, modelo de precios en tiempo real, también se ha presentado brevemente anteriormente.

  • Modelo de precio de cierre

    Cuando se ejecuta el código de la estrategia, el ciclo de la barra de la línea K actual se ejecuta completamente, y cuando la barra de la línea K se cierra, el ciclo de la línea K ha terminado. En este momento se ejecuta una vez más la lógica de la estrategia Pine, y la señal de transacción desencadenada se ejecutará al comienzo de la siguiente barra de la línea K.

  • Modelo de precios en tiempo real

    Cuando se ejecuta el código de la estrategia, la barra de la línea K actual, sea cerrada o no, ejecuta la lógica de la estrategia de Pine una vez por cada cambio de movimiento, y la señal de transacción desencadenada se ejecuta inmediatamente.

Cuando la estrategia del lenguaje Pine se ejecuta de izquierda a derecha en el gráfico, la barra de líneas K en el gráfico se divide en历史Bary实时Bar¿Qué es eso?

  • Bar de la historia

    Cuando se inicia la ejecución de la estrategia configurada como "modelo de precios reales", todas las barras K de la gráfica, excepto la barra K de la parte más derecha, son历史Bar◦ La lógica de la estrategia en cada uno历史BarSe ejecutará una sola vez.
    Cuando se inicia la ejecución de una estrategia configurada como "modelo de precio de cierre", todas las barras en el gráfico son历史Bar◦ La lógica de la estrategia en cada uno历史BarSe ejecutará una sola vez.

    Los cálculos basados en la barra de historial:
    El código de la estrategia se ejecuta una vez en la barra de historia cerrada, y luego continúa ejecutándose en la siguiente barra de historia hasta que todas las barras de historia se ejecuten una vez.

  • Bar en tiempo real

    Cuando la estrategia se ejecuta en la última barra de la línea K de la parte más derecha, la barra es la barra real. Cuando la barra real se cierra, la barra se convierte en una barra pasada (y se convierte en una barra histórica). La parte más derecha de la gráfica genera una nueva barra real.

    Cuando la estrategia se configura como "modelo de precios en tiempo real" para comenzar a ejecutarse, se ejecuta una lógica de estrategia por cada cambio de movimiento en la barra en tiempo real.
    Cuando se inicia la ejecución de una estrategia configurada como "modelo de precio de cierre", el gráfico no muestra la barra en tiempo real.

    Basado en el cálculo de Bar en tiempo real:
    Si la estrategia está configurada como un gráfico de "modelo de precio de cierre" y no muestra la barra en tiempo real, el código de la estrategia se ejecuta solo una vez al cierre de la barra actual.
    Si la política se configura como "modelo de precio de mercado real", el cálculo en la barra de tiempo real y el historial en la barra de tiempo real son completamente diferentes, y cada cambio en la barra de tiempo real ejecuta un código de política. Por ejemplo, las variables incorporadashighlowcloseEn el Bar histórico es cierto, en el Bar en tiempo real es posible que estos valores cambien cada vez que la situación cambia. Por lo tanto, los indicadores y otros datos calculados en base a estos valores también cambian en tiempo real.closeEl precio es el precio actual, y el precio de venta es el precio actual.highylowSiempre representan los máximos y mínimos alcanzados desde el inicio de la barra en tiempo real actual. Estas variables incorporadas representan los valores finales de la última actualización de la barra en tiempo real.

    Mecanismo de retroceso en la ejecución de la estrategia en el Bar en tiempo real (modelo de precios en tiempo real):
    En la ejecución de Bar en tiempo real, cada nueva generación de la estrategia ejecuta una variable definida por el usuario preestablecido, conocida como revertir. Para entender el mecanismo de revertir con un ejemplo, el siguiente código de prueba.

    Aviso:

    /*backtest ... .. . */

    El paquete contiene información de configuración de retroalimentación guardada en código en la plataforma FMZ.

    pine
    /*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")

    img

    img

    En realidad, sólo estudiamos las escenas que se ejecutan en el Bar en tiempo real, así que usamosnot barstate.ishistoryLa restricción de expresión se aplica solo a las variables n en tiempo real en Bar, y se usa antes y después de ejecutar la operación de acumulación.runtime.logLa información de salida de la función está en el registro de la política.plotLa curva trazada n se puede ver cuando la estrategia se encuentra en la barra de historial y n siempre es 0. Cuando se ejecuta en la barra de tiempo real, se desencadena una operación de n + 1 y se ejecuta una operación de n + 1 en cada ronda de ejecución de la estrategia en la barra de tiempo real. Se puede observar a partir de la información del registro que cada ronda de ejecución del código de la estrategia n se restablece al valor final de la anterior ejecución de la estrategia Bar.

    En resumen:

    1. La estrategia se ejecuta una vez cada vez que se actualiza el código de la estrategia cuando la barra de tiempo real se inicia.
    2. Cuando se ejecuta en la barra de tiempo real, se vuelve a rodar la variable antes de ejecutar el código de la política.
      3 Cuando se ejecuta en la barra de tiempo real, la variable se presenta una vez en la actualización de cierre.

    Las operaciones de dibujo, como las curvas en el gráfico, también pueden causar un rediseño debido a la regresión de los datos, por ejemplo, si modificamos el código de prueba que acabamos de probar, prueba en disco:

    pine
    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")

    Captura de pantalla del momento A
    img

    Captura de pantalla del momento B
    img

    La única cosa que hemos cambiado es esta frase:n := open > close ? n + 1 : nEn la primera gráfica (momento A) se agrega n, ya que el precio de apertura es más alto que el precio de cierre (momento B), la curva de la gráfica muestra el valor de 5 . Luego, la tendencia cambia, el precio se actualiza como se muestra en la segunda gráfica (momento B). En esta ocasión, el precio de apertura es inferior al precio de cierre (momento A), el valor de n se retrasa y no se agrega 1. La curva de la gráfica n también se vuelve a dibujar de inmediato, en esta ocasión, la curva de n es de 4.

  • Contexto de las variables en la función

    A continuación, vamos a estudiar las variables en las funciones de la lengua Pine. De acuerdo con la descripción de algunos de los tutoriales de Pine, las variables en la función y las variables fuera de la función tienen la siguiente diferencia:

    La historia de las variables de la serie utilizadas en la función Pine se crea con cada llamada consecutiva de la función. Si no se llama a la función en cada columna en la que se ejecuta el script, esto dará lugar a diferencias entre los valores de la historia de la serie interna y externa de la función en el bloque local. Por lo tanto, si no se llama a la función en cada columna, las series que utilizan el mismo valor de índice dentro y fuera de la función no citan el mismo punto de historia.

    No importa, lo averiguamos a través de un código de prueba que se ejecuta en FMZ:

    pine
    /*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 detección en funcionamiento

    img

    El código de prueba es más sencillo y se utiliza principalmente para examinar los datos citados de dos maneras:f(a) => a[1]yf2() => close[1]

    • f(a) => a[1]La forma en que la función regresa al final:a[1]

    • f2() => close[1]Utiliza las variables incorporadas directamente:closeLa última función que regresa es ,close[1]

    []Símbolo utilizado para referenciar el valor histórico de una variable de una serie de datos, close[1] es decir, el precio de cierre de la barra anterior al precio de cierre actual. En total, nuestro código de prueba muestra 4 datos en la tabla:

    • plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A")
      Dibujar un carácter A<unk>, color rojo, cuando oneBarInTwo es verdadero, y dibujarlo en la posición (en el eje Y) como:f(close)El valor devuelto es:

    • plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
      Dibujar un carácter en B<unk>, color verde, cuando oneBarInTwo es verdadero, y dibujarlo en la posición (en el eje Y) como:f2()El valor devuelto es:

    • plot(close[2], title = "close[2]", color = color.red, overlay = true)
      La línea de dibujo, de color rojo, se dibuja en la posición (en el eje Y) como:close[2]Es decir, el precio de cierre en la barra de la barra 2a a la izquierda.

    • plot(close[1], title = "close[1]", color = color.green, overlay = true)
      La línea de dibujo, de color verde, se dibuja en la posición (en el eje Y) como:close[1]Es decir, el precio de cierre en la barra del número 1 del lado izquierdo de la barra actual.

    Se puede ver en la secuencia de comandos ejecutados a través de la estrategia de retroalimentación, aunque el dibujo A marca la función utilizadaf(a) => a[1]Y la función de dibujo B marcadof2() => close[1]Se utiliza[1] para referirse a los datos históricos de la serie de datos, pero la posición de los marcadores "A" y "B" en el gráfico es completamente diferente. La posición del marcador "A" siempre cae en la línea roja, es decir, el código de la estrategiaplot(close[2], title = "close[2]", color = color.red, overlay = true)En la línea que se dibuja, los datos que se usan son:close[2]

    img

    La razón es que el índice a través de la barra de la línea K, es decir, las variables incorporadasbar_indexCalcular si se dibujan las marcas "A" y "B". Las marcas "A" y "B" no se dibujan en cada barra de línea K.f(a) => a[1]Los valores que se citan de esta manera se relacionan con la función si la función no se llama en cada barra.f2() => close[1]Este modo de citar los valores es diferente (aunque se utilice[1] con el mismo índice) [2].

  • Algunas funciones incorporadas necesitan ser calculadas en cada barra para calcular correctamente su resultado.

    Un ejemplo simple de esto es:

    pine
    res = close > close[1] ? ta.barssince(close < close[1]) : -1 plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)

    Vamos a llamar a la función de códigota.barssince(close < close[1])Se escribe en un operador triangularcondition ? value1 : value2Esto ha llevado a que sólo enclose > close[1]Cuando se llama a la función ta.barssince.ta.barssinceLa función se calcula desde la última vezclose < close[1]El número de líneas K al momento de la creación. La función ta.barssince se llama 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 cuya condición es close < close[1] no se ha establecido, ni tampoco la última vez que se estableció.

    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 la figura:

    img

    Por lo tanto, cuando se dibuja el gráfico, solo se dibuja el dato cuando la variable res tiene un valor ((-1) }}.

    Para evitar este problema, sólo tenemos queta.barssince(close < close[1])La llamada de la función toma el operador triangular y lo escribe en la parte externa de cualquier posible subdivisión condicional. Esto hace que el cálculo se realice en cada barra de la línea K.

    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)

    img

Secuencia de tiempo

El concepto de secuencia temporal es muy importante en el lenguaje Pine, es un concepto que debemos entender cuando aprendemos el lenguaje Pine. La secuencia temporal no es un tipo, sino una estructura básica para almacenar una serie de valores de las variables a lo largo del tiempo. Sabemos que los scripts de Pine están basados en gráficos, y el contenido más básico que se muestra en los gráficos es el gráfico de líneas K. La secuencia temporal en la que cada valor está asociado a una barra de tiempo de una barra de líneas K.openEs una variable interna en el lenguaje Pine, cuya estructura es la secuencia de tiempo de almacenamiento de los precios de apertura de cada línea K de Bar. Se puede interpretar comoopenEsta estructura de secuencia de tiempo representa el precio de apertura de todas las barras de la línea K desde el primer bar en el inicio de la línea K hasta el bar ejecutado en el guión actual. Si la línea K actual es de 5 minutos de duración, entonces en el código de la estrategia de Pine utilizamos la referencia ((o))openEl precio de apertura de la barra de línea K en la ejecución actual del código de la estrategia.[]El operador <unk> se utiliza cuando la estrategia Pine se ejecuta en una barra de línea K.open[1]Indicación de las referenciasopenEl precio de apertura de la barra de línea K anterior a la barra de línea K ejecutada por el guión actual en la secuencia de tiempo (es decir, el precio de apertura del ciclo de línea K anterior).

  • Las variables en la secuencia de tiempo son muy fáciles de calcular
    Lo que hacemos es que tenemos una función interna.ta.cumPor 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 prueba:

    pine
    v1 = 1 v2 = ta.cum(v1) plot(v1, title="v1") plot(v2, title="v2") plot(bar_index+1, title="bar_index")

    Hay muchas similitudes.ta.cumEste tipo de función incorporada puede procesar directamente datos en una secuencia de tiempo, por ejemplota.cumEs decir, sumamos los valores correspondientes de las variables transmitidas en cada barra de la línea K, y luego usamos un gráfico para facilitar la comprensión.

    El proceso de ejecución de la estrategia es la variable bar_index
    | - | - | - | - |
    La estrategia se ejecuta en la primera línea de K-Bar de 0 y 1 y 1 y 1 y 2.
    La estrategia se ejecuta en la segunda línea K-Bar.
    La estrategia se ejecuta en la tercera raíz de K, la barra de la raíz 2 y la raíz 1 y la raíz 3.
    |...|...|...|...|
    Las estrategias se ejecutan en la primera línea de K de N + 1.

    Se puede ver que en realidad v1, v2 e incluso bar_index son estructuras de secuencias de tiempo, y en cada barra hay datos correspondientes. Este código de prueba no se distingue entre el "modelo de precios en tiempo real" o el "modelo de precios de cierre" solo para mostrar el Bar en tiempo real en el gráfico. Para medir la velocidad, usamos la prueba de retroalimentación del "modelo de precios de cierre".

    img

    Porque v1 es igual a 1 en cada barra.ta.cum(v1)La función se ejecuta en la primera línea K Bar, y dado que solo hay una primera línea Bar, se calcula el resultado como 1, y se asigna un valor a la variable v2。
    Cuandota.cum(v1)Cuando se ejecuta en la segunda línea K Bar, ya hay 2 líneas K Bar ((la primera corresponde a la variable interna bar_index es 0, la segunda corresponde a la variable interna bar_index es 1), por lo que se calcula el resultado es 2, dando un valor a la variable v2, y así sucesivamente. En realidad se puede observar que v2 es el número de líneas K Bar en la gráfica, ya que el índice de las líneas Kbar_indexEntonces, si el valor de 0 es 0 y el valor de 0 es 0.bar_index + 1En realidad, es el número de líneas de K.v2ybar_indexEs cierto que coinciden.

    img

    También puedo usarta.cumLa función interna calcula la suma de los precios de cierre de todas las barras de la gráfica actual, que se puede escribir así:ta.cum(close), cuando la estrategia se ejecuta en la barra de tiempo real de la parte derechata.cum(close)El resultado calculado es la suma de los precios de cierre de todas las barras de la tabla (sin ejecutar hasta el lado más a la derecha, solo se suma a la barra actual).

    Las variables en la secuencia de tiempo también se pueden calcular con operadores, como por ejemplo:ta.sma(high - low, 14)Las variables incorporadashigh(El precio más alto de la línea K Bar) menoslow(Precio mínimo de K-Line Bar), el último usota.smaLa función busca el promedio.

  • Los resultados de las llamadas de funciones también dejan huellas de valores en la secuencia 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 en la prueba de retroalimentación y se observav1yv2Los valores de la función son los mismos, y las líneas dibujadas en el gráfico también se superponen completamente. Los resultados de las llamadas a la función pueden dejar huellas de valores en la secuencia de tiempo, como el códigota.highest(high, 10)[1]Entre ellosta.highest(high, 10)Los resultados de las llamadas a funciones también pueden usarse.[1] para citar su valor histórico. Basado en la barra anterior de la barra actualta.highest(high, 10)El resultado es:ta.highest(high[1], 10)Por eso.ta.highest(high[1], 10)yta.highest(high, 10)[1]El mismo precio.

    Verificación de la información de salida con otra función de gráfico:

    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)

    Los valores de las variables a y b de la secuencia temporal se muestran arriba y abajo de la barra correspondiente. El código de dibujo se puede conservar durante el aprendizaje, ya que puede ser necesario producir información en la tabla para su observación durante las pruebas.

    img

Estructura del guión

Estructura general

En la parte inicial del tutorial hemos resumido algunas de las diferencias entre el uso del lenguaje Pine en FMZ y en Trading View.indicator()strategy()Y, por ahora, no lo apoyaré.library()Por supuesto, para ser compatible con las versiones anteriores del guión de Pine, las estrategias se escribieron como://@version=5indicator()strategy()Algunas configuraciones de la política también están disponibles enstrategy()Configuración de los parámetros de transmisión de la función.

<version> <declaration_statement> <code>

<version>La información de control de versión puede ser omitida.

Comentarios

El uso de la lengua Pine//Como comentario de una sola línea, ya que el lenguaje Pine no tiene comentarios de varias líneas./**/Se usa para comentarios de varias líneas.

Código

Las líneas que no son comentarios o instrucciones del compilador en un script son declaraciones, que implementan el algoritmo del script. Una declaración puede ser uno de estos elementos.

  • Declaración de las variables
  • Revalorización de las variables
  • Declaración de la función
  • Invocación de funciones integradas y definidas por el usuario
  • ifforwhileoswitchEstructura de las placas

Las oraciones se pueden ordenar de muchas maneras.

  • Algunas declaraciones pueden expresarse en una sola línea, como la mayoría de las declaraciones de variables, que contienen una sola línea de llamada de función o una declaración de función de una sola línea. Otras, como las estructuras, siempre requieren más de una línea, ya que requieren un bloque local.
  • Las declaraciones en el ámbito global de un script (es decir, las partes que no pertenecen a bloques locales) no pueden ser consideradas空格o制表符Las líneas que comienzan en la primera posición de la línea, por definición, forman parte del alcance global del script.
  • Una estructura o una declaración de funciones de varias líneas siempre requiere unlocal blockUn bloque local debe resumir en un marcador o en cuatro espacios (de lo contrario, se analizará como una secuencia de la línea anterior de código, es decir, se juzgará como un contenido continuo de la línea anterior de código), y cada bloque local define un rango local diferente.
  • Las oraciones de una sola línea se pueden enrolar en una línea usando el comma ((,) como separador.
  • Una línea puede contener comentarios o simplemente comentarios.
  • Las líneas también pueden ser envueltas (continúa en varias líneas).

Por ejemplo, se incluyen tres bloques locales, uno en la declaración de la función personalizada y dos en la declaración de la variable con la estructura if, con el siguiente código:

pine
indicator("", "", true) // 声明语句(全局范围),可以省略不写 barIsUp() => // 函数声明(全局范围) close > open // 本地块(本地范围) plotColor = if barIsUp() // 变量声明 (全局范围) color.green // 本地块 (本地范围) else color.red // 本地块 (本地范围) runtime.log("color", color = plotColor) // 调用一个内置函数输出日志 (全局范围)

Cambiar el código

Las líneas largas pueden ser divididas en varias líneas, o "envueltas". Las líneas envueltas deben reducirse en cualquier cantidad de espacios, siempre que no sea un múltiplo de 4.

pine
a = open + high + low + close

Puede ser envasado en (tenga en cuenta que el número de espacios en cada línea no es un múltiplo de 4):

pine
a = open + high + low + close

Una llamada a una trama larga puede ser empaquetada como ▽.

pine
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)

Las oraciones en las declaraciones de funciones definidas por el usuario también pueden ser empaquetadas. Sin embargo, debido a que el bloque local debe comenzar gramaticalmente con una contracción (((4 espacios o 1 símbolo), cuando se divide a la siguiente línea, la parte de continuación de la oración debe comenzar con una contracción o más ((( no es igual a un múltiplo de 4 espacios)).

pine
test(c, o) => ret = c > o ? (c > o+5000 ? 1 : 0): (c < o-5000 ? -1 : 0) a = test(close, open) plot(a, title="a")

Identificadores y operadores

Identificador

Antes de entender las variables, primero debemos entender el concepto de la etiqueta de identificación de la barra. La etiqueta de identificación de la barra común se utiliza comofunciónyLas variablesLos nombres de las variables y las funciones.funciónComo veremos en el siguiente tutorial, primero aprendemos el código de identificación de la hormiga <unk>。

    1. El identificador debe estar en mayúsculas(A-Z)o en minúsculas(a-z)Las letras o el sublinado(_)Inicio, como el primer carácter del identificador.
    1. El siguiente carácter después del primer carácter del identificador puede serLas letrasBaja líneaoLos números
    1. El nombre del identificador está en mayúsculas.

Por ejemplo, los siguientes identificadores:

pine
fmzVar _fmzVar fmz666Var funcName MAX_LEN max_len maxLen 3barsDown // 错误的命名!使用了数字字符作为标识符的开头字符

Al igual que la mayoría de los lenguajes de programación, el lenguaje Pine también tiene sugerencias de escritura. Por lo general, se recomienda que los nombres de los identificadores:

  • 1 , todas las letras mayúsculas se utilizan para nombrar las constantes .
    1. UsoLas reglas de los picos del camelloNombres para otros identificadores.
pine
// 命名变量、常量 GREEN_COLOR = #4CAF50 MAX_LOOKBACK = 100 int fastLength = 7 // 命名函数 zeroOne(boolValue) => boolValue ? 1 : 0

El operador

Los operadores son símbolos de operación en un lenguaje de programación que se utilizan para construir expresiones, mientras que las expresiones son reglas de cálculo diseñadas para algún tipo de cálculo cuando escribimos una estrategia. Los operadores en el lenguaje Pine se clasifican en función de:

Los operadores de asignación de valor, los operadores de cálculo, los operadores de comparación, los operadores lógicos,? : El operador terciario.[]El operador de referencia de la historia.

Con el operador aritmético*Por ejemplo, para diferenciar el tipo de problema que produce el resultado de la operación de lenguaje Pine en Trading View, hay el siguiente código de prueba:

pine
//@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)

El error de compilación al ejecutar este script en Trading View se debe a queadjustedLength = lenInput * factorDespués de la multiplicación, el resultado esseries intSin embargo,ta.emaEl segundo parámetro de la función no admite este tipo de código. Sin embargo, en FMZ no hay restricciones estrictas de este tipo, y el código anterior funciona correctamente.

A continuación veremos el uso de los diferentes operadores.


Operador de asignación

Hay dos tipos de operadores de asignación:=:=En la parte inicial de este tutorial hemos visto algunos ejemplos.

=El operador se utiliza para dar un valor a una variable cuando se inicializa o declara.=Las variables después de la inicialización y la declaración de la asignación de valor comenzarán con ese valor en cada barra posterior. Estas son declaraciones de variables 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)

Avisoa = closeDeclaración de valoración, en cada barra de la variable a es el precio de cierre actual de la barra ((close) }}. Otras variablesbcdEs invariable y se puede probar en el sistema de retroalimentación en la FMZ, y los resultados se pueden ver en el diagrama.

:=Se utiliza para reasignar valores a variables existentes, y se puede entender simplemente como el uso de:=Un operador es una variable que se utiliza para modificar el valor de una variable que ya ha sido declarada e inicializada.
Si se utiliza:=Un operador que asigna un valor a una variable que no ha sido iniciada o declarada puede generar errores, por ejemplo:

pine
a := 0

Así que,:=Los operadores de asignación se usan generalmente para reasignar una variable existente, por ejemplo:

pine
a = close > open b = 0 if a b := b + 1 plot(b)

¿Cuál es el resultado?close > open(es decir, el BAR actual es la línea de sol), la variable a es el valor verdadero (true) <unk> ejecuta el código en el bloque local de la declaración ifb := b + 1, usando el operador de asignación:=Se le da una nueva asignación a b, se añade un 1 ◦ y luego se usa la función plot para dibujar en la tabla los valores de la variable b en cada BAR de la secuencia de tiempo, en línea ◦

¿Estamos pensando que si hay una línea de sol BAR, b continuará acumulando 1? Por supuesto que no, aquí no usamos ninguna palabra clave cuando declaramos a la variable b y la inicializamos como 0.b=0Se ejecuta en cada BAR, así que se puede ver que el resultado de este código es que se vuelve a poner la variable b a 0 cada vez, si la variable a es verdadera, entonces cumple conclose > openEntonces, en esta ronda de ejecución de código, b se agregará a 1, en el gráfico de la función de trazado, b es 1, pero en la siguiente ronda de ejecución de código, b se reasignará a 0. Aquí también es donde los principiantes del lenguaje Pine pueden tropezar fácilmente.

En cuanto a los operadores de asignación, hay dos palabras clave que hay que ampliar:varvarip

  • var

    Esta es una palabra clave que ya hemos visto y usado en otros tutoriales, pero que no hemos explorado en detalle.

    var es una palabra clave utilizada para asignar y initializar variables una vez. Generalmente, la sintaxis de asignación de variables que no incluye la palabra clave var provoca que los valores de las variables se cubran cada vez que se actualizan los datos. Por el contrario, cuando se utilizan las variables de asignación de la palabra clave var, se mantienen en su estado original a pesar de la actualización de los datos.

    Así que vamos a usar este ejemplo, pero vamos a usar este ejemplo cuando asignamos a b.varLas palabras clave:

    pine
    a = close > open var b = 0 if a b := b + 1 plot(b)

    varLa palabra clave permite que la variable b sólo ejecute la asignación inicial por primera vez, y luego no se restablece a b a 0 cada vez que se ejecuta la lógica de la política, por lo que la línea dibujada en el momento de la ejecución se puede observar b, es decir, el número de rayos B que han aparecido en el BAR de la línea K en el momento de la medición.

    Las variables de la declaración var pueden ser escritas no solo en el ámbito global, sino también en bloques de código, como en este ejemplo:

    pine
    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 'a' mantiene el precio de cierre de la primera columna de la serie.
    La variable 'b' mantiene el precio de cierre de la primera barra de precios de aluminio verde de la serie.
    La variable 'c' mantiene el precio de cierre de la décima naranja verde de la serie.

  • varip

    varipLa primera vez que vimos esta palabra clave, podemos ver la descripción de la misma:

    varip ((var intrabar persist) es una palabra clave utilizada para asignar y initializar variables una vez. Es similar a la palabra clave var, pero las variables que usan la declaración varip conservan su valor entre las actualizaciones de la línea K en tiempo real.

    ¿Es más difícil de entender? No importa, lo explicamos con ejemplos, es fácil de entender.

    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 prueba tiene un comportamiento diferente en el modelo de precios de cierre y en el modelo de precios en tiempo real:

    Modelo de precios en tiempo real:
    ¿Recuerdan que la estrategia que hemos explicado anteriormente se ejecuta en una etapa de BAR histórica y una etapa de BAR en tiempo real?varvaripVariables declaradasiiiCada vez que se ejecuta el código de la estrategia, se ejecuta una operación de incremento. Por lo tanto, se puede ver que los números que se muestran en la línea KBAR de los resultados de la retroalimentación aumentan 1 cada uno. Cuando termina la etapa histórica de la línea K y comienza la etapa de la línea K en tiempo real, las variables de las declaraciones var y varip comienzan a cambiar.i := i + 1yii := ii + 1La diferencia es que ii se modifica cada vez que se ejecuta. Aunque i también se modifica cada vez, el siguiente ciclo de ejecución de la lógica de la estrategia restablece el valor anterior (¿recuerdas el mecanismo de retroceso que explicamos en el capítulo anterior "Ejecución del modelo"?) hasta que la línea KBAR actual se completa para actualizar el valor de determinación de i (es decir, el siguiente ciclo de ejecución de la lógica de la estrategia no restablece el valor anterior). Así que se puede ver que la variable i sigue aumentando por cada barra.

    Modelo de cierre de la operación:
    Dado que el modelo de precio de cierre es una lógica de estrategia que se ejecuta cuando cada línea K BAR termina. Así, en el modelo de precio de cierre, las etapas históricas de la línea K y las etapas de la línea K en tiempo real, las variables de las declaraciones var, varp se muestran de forma progresiva en el ejemplo anterior, aumentando 1 por cada línea K BAR.


Operador de aritmética
El operadorilustrar
+Añadido
-La ley de la deducción
*La multiplicación
/Eliminación de las leyes
%Buscar ejemplos

+-Un operador puede ser usado como un operador binario o un operador unitario. Otros operadores aritméticos solo pueden ser usados como un operador binario, y si se usan como un operador unitario se producen errores.

1 , el operador aritmético es de tipo numérico en ambos lados, el resultado es de tipo numérico, entero o número de puntos flotantes dependiendo del resultado de la operación.
2. Si el número de operaciones es una cadena, el operador es+, se calcula como una cadena, los valores se convierten en forma de cadena, y luego las cadenas se entrelazan. Si se trata de otro operador de aritmética, se intenta convertir la cadena en un valor y luego se opera.
3. Si el número de operaciones es na, el resultado es nulo, y se muestra NaN cuando se imprime en la FMZ.

pine
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, ya que no es muy exigente o estricto con los requisitos de tipo de variable. Por ejemplo:

pine
a = 1 * "1.1" b = "1" / "1.1" c = 5 % "A" plot(a) plot(b) plot(c)

En FMZ es posible, pero en la vista de trading se reportará un error de tipo. Para los operadores de cálculo, cuando los números operativos de ambos lados son cadenas, el sistema calcula las cadenas después de convertirlas en valores numéricos. Si las cadenas no numéricas no se pueden calcular, el resultado de la operación del sistema es un valor nulo.


Comparar el operador

El operador de comparación es un operador binario.

El operadorilustrar
<Menos de
>Más que
<=Menos es igual a
>=Más grande es igual a
==El mismo.
!=Desigualdad

Ejemplo de prueba:

pine
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 se puede ver, el operador de comparación es muy sencillo de usar, pero es también el operador que más usamos al escribir políticas. Se puede comparar valores, pero también se pueden comparar variables incorporadas, por ejemplocloseopenesperar.
Al igual que los operadores de cálculo, en la FMZ hay una diferencia con el Pine de Trading View, la FMZ no tiene un tipo de requerimiento especialmente estricto, por lo que este tipo de declaracionesd = "1" >= 2 En FMZ no hay error, la ejecución se convierte primero en una cadena de valores y luego se compara. En Trading View hay error.


Operador lógico
El operadorSímbolo del códigoilustrar
NonotOperador unitario, no operativo
yandOperador binario que opera con y
oorOperador binario, o operación

Si hablamos de operadores lógicos, entonces debemos hablar de tablas de valores reales. Al igual que aprendimos en la escuela secundaria, solo que aquí estamos probando y aprendiendo en el sistema de retroalimentación:

pine
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 el sistema de retroalimentación se vea afectado por la información que se imprime constantemente, usamosruntime.error("stop")Una vez ejecutada la impresión, se produce un error excepcional que detiene la medición, y luego se puede observar la información de salida, y se puede encontrar que el contenido de la impresión y la tabla de valores reales son en realidad los mismos.


El operador de trinidad

Utilizando el operador triangular? : Expresiones trigonométricas combinadas con números operativoscondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseEn el curso anterior ya estábamos familiarizados con el término. Las denominadas expresiones tridimensionales, los operadores tridimensionales, significan que hay tres operaciones en total.

condition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse¿Qué es lo que pasa?conditionEs decir, si el valor de la expresión de la regla verdadera es:valueWhenConditionIsTrueSi es así.conditionEl valor para la expresión hipotética esvalueWhenConditionIsFalse

A pesar de que no tiene mucha utilidad práctica, los ejemplos que se pueden usar son fáciles de mostrar:

pine
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)

No importa lo que hagas si te encuentras con una cruz. Las expresiones tridimensionales también pueden ser empotradas, como ya hicimos en el tutorial anterior.

pine
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)

En realidad es lo mismo quecondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseEnvalueWhenConditionIsTruevalueWhenConditionIsFalse, también se usa otra expresión trinomial en su lugar.


Operador de historial

Utilizando el operador histórico[]Los valores históricos en la secuencia de tiempo de referencia. Estos valores históricos son los valores de la variable en la línea K BAR anterior a la línea K BAR actual cuando se ejecuta el script.[]El operador se utiliza después de las llamadas de variables, expresiones y funciones.[]El valor en este paréntesis cuadrado es el desplazamiento de la data histórica a la que queremos referir desde la línea BAR de la línea K actual. Por ejemplo, si quisiera citar el precio de cierre de la línea BAR de la línea K anterior, escribiría:close[1]

En las lecciones anteriores hemos visto una forma similar de escribir:

pine
high[10] ta.sma(close, 10)[1] ta.highest(high, 10)[20] close > nz(close[1], open)

[]El operador solo puede ser usado una vez en el mismo valor, por lo que esto es incorrecto y se equivocará:

pine
a = close[1][2] // 错误

Tal vez vean aquí, algunos de sus compañeros de clase dirán que el operador[]Es para la estructura de series, que parece ser muy parecida a la estructura de series (series) y a la de arrays.
A continuación, vamos a usar un ejemplo para mostrar la diferencia entre series y arrays en el lenguaje Pine.

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")

Aunque se dicea = close[1][2]Es una forma equivocada de escribir esto, pero:

pine
b = close[1] c = b[1]

En este caso, el valor de la matriz es el valor de la matriz, y el valor de la matriz es el valor de la matriz, y la matriz es el valor de la matriz.b = close[1]Después de la asignación, b debería ser un valor, sin embargoc = b[1], b todavía puede ser usado de nuevo por el operador histórico para citar el valor histórico. Se puede ver que el concepto de serie en el lenguaje de Pine no es tan simple como el de un conjunto. Se puede entender como el valor histórico de la barra anterior cercana, b es también una estructura de secuencia de tiempo, y se puede seguir citando su valor histórico.

Podemos mover el gráfico hacia abajo a la izquierda y ver que en la primera línea K, los valores de b y c son valores nulos ((na)). Esto se debe a que cuando el script se ejecuta en la primera línea K BAR, los valores históricos de referencia de uno o dos ciclos hacia adelante no existen. Por lo tanto, debemos tener en cuenta a menudo cuando escribimos estrategias si se hace referencia a valores nulos cuando se hace referencia a datos históricos.nanzLa función interna es la que juzga si la función es correcta o no, y la función interna es la que juzga si la función es correcta o no.nznaFunciones, ¿recuerdas en qué capítulo?) que tratan específicamente los casos de valores vacíos, por ejemplo:

pine
close > nz(close[1], open) // 当引用close内置变量前一个BAR的历史值时,如果不存在,则使用open内置变量

Esto es un tratamiento para el que se puede citar el valor nulo ((na)).


Prioridad del operador

Hemos aprendido muchos de los operadores de la lengua Pine, que forman expresiones a través de varias combinaciones de números y operaciones. Entonces, ¿cuál es la prioridad de estas operaciones cuando se calcula en expresiones?

Las prioridadesEl operador
9[]
8El operador de unidad +- y ``` not ``
7*/%
6El operador binario +-
5><>=<=
4==!=
3and
2or
1?:

Las partes de la expresión que tienen una alta prioridad se operan primero, y si tienen la misma prioridad se operan de izquierda a derecha. Si se quiere forzar la primera operación de una parte, se puede usar()Envuelve una expresión que requiere una operación de esta parte primero.

Las variables

Declaración de las variables

Ya hemos aprendido el concepto de la etiqueta de la variable, la etiqueta de la variable es el nombre que se le da a la variable. Por lo tanto, también se dice: la variable es el identificador del valor guardado. Entonces, ¿cómo se declara una variable?

  • Modelo de declaración:
    La primera palabra que se escribe cuando se declara una variable es "modo de declaración". Hay tres modos de declaración de variables:

    1. Utiliza las palabras clavevar
    2. Utiliza las palabras clavevarip
    3. No escribo nada.

    varvaripLa palabra clave es algo que ya hemos aprendido en el capítulo anterior "Operadores de asignación" y que no vamos a mencionar aquí. Si el modelo de declaración de la variable no escribe nada, por ejemplo, la frase:i = 1En realidad, como hemos dicho antes, las variables que se declaran y se asignan se ejecutan en cada línea KBAR.

  • tipo
    El lenguaje Pine en FMZ no es estricto en cuanto a los requisitos de tipo, y generalmente se puede omitir. Sin embargo, para compatibilidad con las políticas de scripts en Trading View, las variables también pueden tener tipo cuando se declaran. Por ejemplo:

    int i = 0 float f = 1.1

    Los tipos en Trading View son más exigentes, y se producen errores si se usa el siguiente código en Trading View:

    baseLine0 = na // compile time error!
  • Identificador
    El nombre del identificador es el nombre de la variable, el nombre del identificador se ha mencionado en el capítulo anterior, se puede ver en: https://www.fmz.com/bbs-topic/9390#标识符

En resumen, la declaración de una variable puede escribirse así:

// [<declaration_mode>] [<type>] <identifier> = value 声明模式 类型 标识符 = 值

Aquí se usa el operador de asignación:=Asignar un valor a una variable en una declaración de variables. Cuando se asigna un valor, el valor puede ser una cadena, un valor, una expresión, una llamada de función, o un número.ifforwhileoswitchEstas estructuras de palabras clave, sentencias y usos se explicarán en detalle en los siguientes cursos, de hecho, hemos aprendido la asignación de sentencias if simples en los cursos anteriores, y podemos repasarlos).

Aquí nos centramos en la función de entrada, una función que usamos con mucha frecuencia cuando diseñamos y escribimos estrategias. Es una función muy importante en la estrategia de diseño.

Funciones de entrada:

input函数,参数defval、title、tooltip、inline、group

La función de entrada en FMZ es un poco diferente a la de Trading View, pero se utiliza como entrada asignada a los parámetros de la estrategia. A continuación, detallamos el uso de la función de entrada en FMZ con un ejemplo:

pine
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)

Los controles soportados en FMZ actualmente incluyen entradas de valores, entradas de texto, tiradores y selección de valores. También se puede configurar el grupo de parámetros de la política, así como información de texto de sugerencia para configurar los parámetros.

img

A continuación se presentan algunos de los principales parámetros de la función de entrada:

  • defval: es el valor predeterminado de la opción de parámetro de la política de configuración de la función de entrada, con soporte para variables, valores y cadenas de caracteres integrados en el lenguaje Pine
  • title: el nombre de los parámetros que la política muestra en la interfaz de la política en disco/retrospectiva.
  • tooltip: Información de aviso de los parámetros de la política, cuando el ratón se cuelga sobre los parámetros de la política, se muestra la información de texto de la configuración de este parámetro.
  • group: nombre del grupo de parámetros de la política, al que se le puede dar el grupo de parámetros ∂.

Además de las declaraciones y asignaciones de variables individuales, el lenguaje Pine también declara un conjunto de variables y asigna un valor:

[变量A,变量B,变量C] = 函数 或者 ```if```、 ```for```、```while```或```switch```等结构

La más común es la que usamosta.macdCuando la función calcula el MACD, como el MACD es un indicador multilineal, calcula tres conjuntos de datos. Por lo tanto, se puede escribir como:

pine
[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)

Es muy sencillo dibujar un gráfico MACD con el código anterior, ya que las funciones incorporadas pueden devolver varias variables y las funciones personalizadas pueden devolver varios datos.

pine
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)

El uso de estructuras como if como asignación de valores a varias variables también es similar a la forma de funciones personalizadas anterior, y los interesados pueden intentarlo.

[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)

Estructura de las condiciones

Algunas funciones no se pueden escribir en bloques de código local de ramificaciones condicionales, principalmente las siguientes:

barcolor(), fill(), hline(), indicator(), plot(), plotcandle(), plotchar(), plotshape()

En Trading View se compilarán los informes de errores. En FMZ, las restricciones no son tan estrictas, pero también se recomienda seguir las normas de Trading View. Por ejemplo, aunque no se informan errores en FMZ, no se recomienda escribir así.

pine
strategy("test", overlay=true) if close > open plot(close, title="close") else plot(open, title="open")

Declaración de si

Un ejemplo:

pine
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: la expresión para juzgar, devuelve un valor de burr. Tenga en cuenta que no puede haber más de una sucursal de else. Todas las expresiones de la sucursal no son verdaderas, y sin la sucursal de else, devuelve na.

pine
x = if close > open close plot(x, title="x")

Debido a que el bloque local de if no se ejecuta cuando la línea K BAR es negativa, es decir, cuando close < open, la expresión después de la frase if es falsa. En este caso tampoco hay una rama else, y la frase if devuelve na. . . . . . . . . . . . . . . . .

Enunciados de switch

Una declaración de switch también es una declaración de estructura ramificada que se utiliza para diseñar diferentes vías de ejecución según ciertas condiciones. Las declaraciones de switch generalmente tienen los siguientes puntos clave de conocimiento:

1, la sentencia switch puede devolver un valor igual que la sentencia if
2. A diferencia de las declaraciones de cambio en otros lenguajes, la ejecución de la estructura de cambio solo ejecuta un bloque local en su código, por lo que la declaración de ruptura no es necesaria (es decir, no se necesita escribir palabras clave como ruptura).
3. cada rama de switch puede escribir un bloque de código local, y la última línea de este bloque de código local es el valor que se devuelve (que puede ser un subgrupo de un valor). Si no se ejecuta ningún bloque de código local de la rama, se devuelve na.
4. La ubicación de la expresión en la estructura de switches, donde se pueden escribir cadenas, variables, expresiones o llamadas de funciones.
5. switch permite especificar un valor de retorno que se utiliza como valor predeterminado cuando no hay otras condiciones en la estructura.

Los switches se dividen en dos formas, y vamos a ver ejemplos de cada una para entender cómo se usan.

1, con una expresiónswitchUn ejemplo:

pine
// 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 habíamos aprendido las funciones de entrada, y aquí continuamos con dos funciones similares a la entrada:input.stringinput.intfunción.
input.stringEl nombre de la secuencia de comandos es el siguiente:input.intFunción que devuelve un valor entero. En el ejemplo se añade una nueva función.optionsEl uso de los parámetros,optionsLos parámetros se pueden pasar a un conjunto de valores seleccionables. Por ejemplo, en el ejemplooptions=["EMA", "SMA", "RMA", "WMA"]yoptions=[5, 10, 20](Tenga en cuenta que uno es un tipo de cadena y el otro es un tipo de valor numérico). Así, los controles en la interfaz de la política no necesitan ingresar valores específicos, sino que se convierten en cajones para seleccionar las opciones que se proporcionan en el parámetro de opciones.

El valor de la variable func es una cadena de caracteres, la variable func como una expresión de la conmutación ((puede ser una variable, una llamada de función, una expresión), para determinar qué rama de la conmutación se ejecuta. Si la variable func no puede coincidir con la expresión en cualquier rama de la conmutación (es decir, es equivalente), se ejecuta el bloque de código de la rama predeterminada, que se ejecutaruntime.error("error")La función hace que la política de lanzamiento de excepciones se detenga.

En nuestro código de prueba de arriba, después de la última línea de runtime.error de la rama de código por defecto de switch, no hemos añadido[Na, na] para compatibilizar el valor de devolución, en la vista de trading es necesario considerar el problema, si el tipo no es consistente, el error será compensado. Pero en FMZ, ya que no hay un tipo de requisito estricto, se puede omitir este código de compatibilidad.

pine
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)

En FMZ no se producen errores, pero en trading view sí. Porque los tipos de las ramas de if son inconsistentes.

  1. sin expresiónswitch

Ahora lo vemos.switchOtra forma de usar el término es escribirlo sin la expresión.

pine
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)

Como se puede ver en el ejemplo de código de prueba, switch coincide con la ejecución de un bloque de código local que es verdadero en términos de ramificación. En general, las condiciones de ramificación después de la sentencia de switch deben ser mutuamente rechazadas. Es decir, en el ejemplo, up y down no pueden ser verdaderos al mismo tiempo.up = close > open // up = close < open Cambiar el contenido de la nota, y volver a medir el resultado que se observa. Encontrará que la rama de switch solo puede ejecutar la primera rama. Además, se debe tener en cuenta que no se debe escribir la llamada de la función en la rama de switch, ya que la función no puede ser llamada en cada BAR, lo que puede causar problemas de cálculo de datos.switchEn el ejemplo, la rama de ejecución está definida y no se cambia en el funcionamiento de la estrategia.)

Estructura del ciclo

Enunciados para

返回值 = for 计数 = 起始计数 to 最终计数 by 步长 语句 // 注释:语句里可以有break,continue 语句 // 注释:最后一条语句为返回值

Las sentencias for son muy sencillas de usar, ya que el ciclo for puede finalmente devolver un valor (en inglés) o devolver varios valores para[a, b, c] como forma de a, b, c) ❚ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦

Utilizado en el ciclo forbreakPalabras clave: Cuando se ejecutabreakDespués de la frase, el ciclo se detiene.
Utilizado en el ciclo forcontinuePalabras clave: Cuando se ejecutacontinueDespués de la frase, el ciclo lo ignora.continueEl código siguiente ejecuta directamente la siguiente ronda de ciclo. La declaración for devuelve el valor devuelto en la última ejecución de ciclo. Si no se ejecuta ningún código, devuelve un valor nulo.

A continuación, mostramos un ejemplo sencillo:

pine
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")

Para ... en la oración

for ... inHay dos formas de sentencias, las que se explican con los siguientes códigos falsos:

返回值 = for 数组元素 in 数组 语句 // 注释:语句里可以有break,continue 语句 // 注释:最后一条语句为返回值
返回值 = for [索引变量, 索引变量对应的数组元素] in 数组 语句 // 注释:语句里可以有break,continue 语句 // 注释:最后一条语句为返回值

Se puede ver que la principal diferencia entre las dos formas radica en el contenido que sigue a la palabra clave for, una de las cuales utiliza una variable como referencia a un elemento de la matriz. Una de ellas utiliza una estructura de referencia que contiene una variable de índice, un subconjunto de variables de un elemento de la matriz.

pine
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")

Cuando se necesita un índice.for [i, ele] in testArray¿Cómo se escribe?

Aplicaciones para el ciclo

Cuando se puede usar una función incorporada proporcionada por el lenguaje Pine para realizar algunos cálculos lógicos circulares, se puede escribir directamente con una estructura circular, o se puede procesar con una función incorporada. Tomemos dos ejemplos.

1 Calcular el promedio

Cuando se usa un diseño de estructura circular:

pine
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)

En el ejemplo se utiliza la suma de for y se calcula el promedio.

La línea media se calcula directamente con la función incorporada:

pine
plot(ta.sma(close, length), title="ta.sma", overlay=true)

Utiliza funciones integradas directamenteta.smaPara calcular el indicador de la línea media, es obvio que es más sencillo usar la función integrada para calcular la línea media. En el gráfico de comparación se puede ver que los resultados calculados son completamente idénticos.

2 La suma

¿Utilizas el ejemplo anterior para ilustrarlo?

Cuando se usa un diseño de estructura circular:

pine
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 la suma de todos los elementos de la matriz, se puede usar el ciclo, o se puede usar una función interna.array.sum¿Qué es lo que está pasando?
La suma se calcula directamente con la función incorporada:

pine
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)

Se puede ver que los datos calculados se muestran perfectamente en el gráfico usando un gráfico.

Entonces, ¿por qué diseñar un ciclo si se puede hacer todo esto con una función incorporada?
1 . Para algunas operaciones de la matriz, cálculo .
2. Revisar la historia, por ejemplo, para averiguar cuántos puntos altos del pasado fueron más altos que los del BAR actual. Dado que los puntos altos del BAR actual solo se conocen en el BAR en el que se ejecuta el script, se requiere un ciclo para regresar a tiempo y analizar los BAR anteriores.
3. Cuando la función interna en el lenguaje Pine no puede completar el cálculo del BAR pasado.

Enunciados mientras

whileLa sentencia permite que el código de la parte del ciclo se ejecute hasta que la condición de juicio de la estructura while sea falsa.

返回值 = while 判断条件 语句 // 注释:语句里可以有break,continue 语句 // 注释:最后一条语句为返回值

Las otras reglas de while son similares a las del ciclo for, donde la última línea del bloque de código local del cuerpo circular es el valor de retorno, que puede devolver varios valores. Cuando la "condición del ciclo" ejecuta el ciclo en tiempo real, el ciclo se detiene cuando la condición es falsa. También se puede usar la frase break, continue en el cuerpo circular.

También puedo mostrar el ejemplo de la línea de medición:

pine
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)

Se puede ver que el uso de while en ciclo también es muy simple, y también se pueden diseñar algunas lógicas de cálculo que no pueden ser reemplazadas por funciones integradas, por ejemplo, la multiplicación por escalas:

pine
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

Unidad

Arrays en el lenguaje de programación Pine y otras definiciones de arrays en lenguajes de programación similares, Arrays de Pine es un conjunto de dimensiones. Se suele utilizar para almacenar una serie continua de datos. Arrays en los que los datos individuales almacenados se llaman elementos del conjunto, los tipos de estos elementos pueden ser: enteros, flotantes, cadenas, valores de color, valores de burr.[]Es necesario usararray.get()yarray.set()La función ◦ es la secuencia de índices de los elementos de la matriz, es decir, el índice del primer elemento de la matriz es 0, y el índice del siguiente elemento es incrementado por 1。

En un código muy simple, explicamos:

pine
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))

Array declarado

usararray<int> afloat[] bUn conjunto de declaraciones o una sola variable puede ser asignado a un conjunto, por ejemplo:

pine
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")

Utilizado generalmente para la inicialización de variables de la matrizarray.newyarray.fromFunción 。 Hay muchas otras funciones similares a array.new relacionadas con el tipo en el lenguaje Pine:array.new_int()array.new_bool()array.new_color()array.new_string()esperar.

La palabra clave var también puede funcionar con el modo de declaración de la matriz, donde la matriz declarada con la palabra clave var sólo se inicializa en la primera línea BAR. Observemos con un ejemplo:

pine
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")

Se puede ver que los cambios de la matriz a se determinan continuamente y no se restablecen. La matriz b se inicializa en cada BAR.barstate.islastPor lo tanto, la impresión en tiempo real sigue teniendo un solo elemento, el valor 0。

Leer y escribir elementos en una matriz

Utiliza array.get para obtener los elementos que se indican en la posición de índice en el array, y utiliza array.set para modificar los elementos que se indican en la posición de índice en el array.

El primer parámetro de array.get es el array a procesar y el segundo es el índice especificado.
El primer parámetro de array.set es el conjunto a tratar, el segundo es el índice especificado, y el tercero es el elemento a escribir.

Para ilustrarlo, utilicemos el siguiente ejemplo:

pine
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 ejemplo inicializa el color base verde, declara e inicializa un array para conservar el color y luego otorga una transparencia diferente a los valores de color (utilizando la función color.new) [2]. Calcula el grado de color calculando la distancia entre el BAR actual y el máximo de 100 ciclos de revisión. Cuanto más cerca del máximo de 100 ciclos de revisión más recientes, más alto es el grado y más profundo es el color correspondiente (baja transparencia).

Recorre los elementos de la matriz

¿Cómo se puede hacer un recorrido por una matriz usando las expresiones for/for in/while que hemos aprendido anteriormente?

pine
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")
pine
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")
pine
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")

Los resultados son los mismos en las tres formas de recorrido.

Los arrays pueden ser declarados en el ámbito global del script, o en el ámbito local de la función o de la rama if.

Cita de datos históricos

Para el uso de elementos en una matriz, la siguiente manera es equivalente, podemos ver en el siguiente ejemplo que dibujamos dos grupos de líneas en la tabla, dos en cada grupo, y los valores de las dos líneas de cada grupo son exactamente los mismos.

pine
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)

Funciones de adición y eliminación de una matriz

  1. Funciones relacionadas con la operación de adición de la matriz:

array.unshift()array.insert()array.push()

  1. Funciones relacionadas con la operación de eliminación de la matriz:

array.remove()array.shift()array.pop()array.clear()

Utilizamos el siguiente ejemplo para probar las operaciones de adición y eliminación de estas matrices:

pine
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")

Aplicaciones para agregar y eliminar: Arrays como colas

Usando una matriz, y algunas de las funciones de adición y eliminación de la matriz, podemos construir una estructura de datos llamada "cuadrilla". La cuadrilla se puede usar para calcular el promedio móvil del precio de tick, y algunos estudiantes pueden preguntar: ¿Por qué construir una estructura de cuadrilla? ¿No podríamos calcular el promedio con una matriz antes?

Una secuencia es una estructura que se utiliza a menudo en la programación. Las características de la secuencia son:

Los elementos que entran primero en la cola salen primero.

Esto asegura que los datos que existen en la cola son los más recientes y que la cola no se expande indefinidamente (el código que se expande indefinidamente solo se puede escribir al mediodía, ya que los problemas se producen entre la mañana y la tarde).

En el siguiente ejemplo, utilizamos una estructura de cola para registrar el precio de cada tick, calcular el promedio móvil a nivel de tick y luego compararlo con el promedio móvil a nivel de línea K de 1 minuto.

pine
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")

Nótese que cuando declaramos una matriz a, especificamos el modo de declaración y usamos la palabra clavevaripAsí, cada cambio de precio se registra en una matriz a.

Funciones de cálculo y operación de matrices de uso común

Calcular las funciones correspondientes:

array.avg()Busquemos el promedio de todos los elementos de la matriz.array.min()Busquemos el elemento más pequeño de la matriz.array.max()Busque el elemento más grande de la matriz.array.stdev()Busque la diferencia estándar de todos los elementos en la matriz.array.sum()Busque la suma de todos los elementos del conjunto.

Funciones relacionadas con la operación:
array.concat()Combinación o conexión de dos series.
array.copy()Copiar una matriz.
array.joinConecta todos los elementos de la matriz en una cadena.
array.sort()En orden ascendente o descendente.
array.reverse()Un conjunto invertido.
array.slice()Se cortan las matrices.
array.includes()El elemento de juicio.
array.indexof()Devuelve el índice en el que apareció por primera vez el valor introducido por el parámetro. Si no encuentra ese valor, devuelve -1.
array.lastindexof()Encuentra el último valor que apareció.

Ejemplos de prueba de funciones relacionadas con el cálculo de matrices:

pine
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 son las funciones de cálculo de array más usadas.

Ejemplos de funciones operativas:

pine
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")

función

Funciones personalizadas

El lenguaje Pine puede diseñar funciones personalizadas, y en general las funciones personalizadas del lenguaje Pine tienen las siguientes reglas:

  1. Todas las funciones están definidas en el ámbito global del script. No se puede declarar una función en otra función.
  2. No permite que una función se llame a sí misma en su propio código.
  3. En principio, todas las lenguas PINE tienen una función de dibujo integradabarcolor()、 fill()、 hline()、plot()、 plotbar()、 plotcandle()) no puede ser invocado dentro de una función personalizada.
  4. Las funciones pueden ser escritas en una sola línea o en varias líneas. El valor de la última frase es el valor de la función actual, y el valor de la función puede ser devuelto en forma de módulo.

También hemos usado funciones personalizadas en tutoriales anteriores, por ejemplo, las funciones personalizadas diseñadas en una sola línea:

pine
barIsUp() => close > open

Esta función devuelve si el BAR actual es el rayo de sol.

Diseño de funciones personalizadas en varias líneas:

pine
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)

Una función de la línea media de sma que nosotros mismos hemos implementado con una función personalizada.

También, se puede devolver un ejemplo de una función de configuración de dos variables:

pine
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)

Una función puede calcular una línea rápida, una línea lenta, dos indicadores de línea media EMA.

Funciones integradas

Las funciones integradas pueden ser fácilmenteFMZ PINE Script DocumentaciónEncuestas en línea

Las funciones integradas en el lenguaje Pine se clasifican:

Funciones de procesamiento de cadenasstr.La serie.
2 Funciones de procesamiento de valores de colorcolor.La serie.
3 , la función de entrada de parámetrosinput.La serie.
4 . Función de cálculo del índiceta.La serie.
5o, las funciones de dibujoplot.La serie.
6 Funciones de procesamiento de arraysarray.La serie.
Funciones relacionadas con la transacciónstrategy.La serie.
Funciones relacionadas con las operaciones matemáticasmath.La serie.
9, otras funciones ((procesamiento de tiempo, serie de dibujo de gráficos no-plot,request.Funciones de serie, funciones de procesamiento de tipos, etc.)

Función de transacción

strategy.Las funciones de serie son las funciones que usamos a menudo en el diseño de estrategias, y están relacionadas con la ejecución de operaciones de transacción cuando la estrategia se ejecuta.


1、strategy.entry

strategy.entryLa función es una función de orden que es muy importante cuando se escribe una estrategia. Algunos de los parámetros más importantes de la función son:id, direction, qty, whenesperar.

parámetro:

  • id: puede entenderse como un nombre que se utiliza para referirse a una posición de negociación. Puede referirse a este id para revocar, modificar órdenes, cerrar posiciones.
  • directionSi la dirección de la orden es hacer más (comprar) este parámetro se transmitestrategy.longEsta variable interna se transmite si se va a hacer un descuento.strategy.shortEsta variable es:
  • qty: Especifica la cantidad de pedidos, si no se transmite este parámetro, se usa la cantidad de pedidos por defecto.
  • when: condición de ejecución, se puede especificar este parámetro para controlar si se activa la operación de la orden actual.
  • limitEspecificar el precio de la orden.
  • stopEl precio de parada es:

strategy.entryDetalles de ejecución de la funciónstrategyEl control de la configuración de los parámetros en la llamada de la función también se puede realizar mediante"Parámetros de modelado de la biblioteca de clases de intercambio de lenguaje Pine".Para más detalles sobre los controles de configuración, los controles de parámetros de la versión de la biblioteca de clases de transacciones en el lenguaje Pine, consulte el documento en el enlace.

¿Qué es lo más importante aquí?strategyEn la función,pyramidingdefault_qty_valueParámetros. Prueba con el siguiente código:

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(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)

Inicio del código/*backtest ... */La parte del paquete es para la configuración de retroalimentación, es para registrar información como la hora de configuración de retroalimentación en ese momento, para facilitar la desinstalación, no el código de la política.

En el código:strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)Cuando lo designamos,pyramidingSi el parámetro es 3, entonces estamos configurando el máximo de tres operaciones en la misma dirección.strategy.entryLa siguiente operación no se ejecutó una vez.default_qty_valueEl parámetro es 0.1, por lo que la identificación de la barra de ID es 1<unk>longstrategy.entryEl número de ordenes por debajo de la operación es el 0.1 que se establece por defecto.strategy.entryCuando la función se llamadirectionEs igual astrategy.longEn la actualidad, el costo de la prueba es de US$1,5 millones, por lo que los pedidos son pagados en la prueba de respuesta.

Nota en el códigostrategy.entry("long3", ...La siguiente operación se llama dos veces, la primera para el mismo ID: <unk>long3<unk>strategy.entryLa siguiente operación no tuvo éxito, segunda llamadastrategy.entryLa función es para modificar el pedido de este ID ((los datos mostrados en la prueba de retroalimentación también pueden mostrar que el pedido de este pedido de precio límite se modificó para 0.3)). En otro caso, por ejemplo, si el primer pedido de ID se transactó con el ID de <unk>long3<unk>, continúe usando el ID de <unk>long3<unk> que se transactóstrategy.entrySi una función es ordenada, entonces la posición de la orden se acumula en ID<unk>long3<unk>.


2、strategy.close

strategy.closeLa función se utiliza para la posición de salida de la posición de entrada que identifica el ID de la posición de salida. Los parámetros principales son:idwhenqtyqty_percent

parámetro:

  • idLa identificación de entrada que se requiere para la liquidación es la que usamos.strategy.entryEl ID que se indica al abrir la posición de la función de pedido de entrada.
  • whenCondiciones de ejecución:
  • qtyLa cantidad de liquidaciones.
  • qty_percentPorcentaje de liquidez.

Para familiarizarse con el uso de esta función, un ejemplo:
En el código/*backtest ... */Es la información de configuración de FMZ.COM en la estación internacional de retrospectiva, puede eliminar, configurar el mercado, la variedad, el rango de tiempo que necesita para la prueba, etc.

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("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

La estrategia de prueba mostró que se comenzó con tres entradas múltiples consecutivas, con ID de entrada de 1 <unk> long, y luego se usóstrategy.closeLos diferentes resultados de las respuestas de los diferentes parámetros de la función se pueden encontrar.strategy.closeEsta función no tiene parámetros para especificar el precio de salida de la posición de liquidación. Esta función se utiliza principalmente para la liquidación inmediata a los precios actuales del mercado.


3、strategy.close_all

strategy.close_allLa función se utiliza para despejar todas las posiciones actuales, ya que los guiones del lenguaje Pine solo pueden tener posiciones en una dirección, es decir, si se activa una señal en la dirección opuesta a la de la posición actual, se despejará la posición actual y se abrirá la posición según la señal.strategy.close_allCuando se llama, se borran todas las posiciones en la dirección actual.strategy.close_allLos principales parámetros de la función son:when

parámetro:

  • whenCondiciones de ejecución:

En este caso, el uso de un ejemplo para observar:

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("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

El código de prueba comienza con una tenencia de 0...strategy.position_size==0es verdadero), por lo que sólo se ejecuta el ID de columna de longitud columna cuando cumple con las condiciones de la configuración del parámetro whenstrategy.entryFunción de entrada: después de tener varias posicionesstrategy.position_sizeMás grande que 0, entonces la función de entrada de ID para la barra de short se puede ejecutar, debido a la posición de los titulares en ese momento, esta señal de inversión de la baja en la bolsa que se produce en este momento puede causar que la posición de los titulares se apague y luego se vuelva a abrir. Luego escribimos en la condición if cuandostrategy.position_size < 0Cuando se mantiene una posición en blanco, se elimina toda la posición en la dirección de la posición actual. Y se marcaenableStop := true│ dejar que la estrategia deje de ejecutarse para poder ver el registro │

Se puede encontrarstrategy.close_allEsta función no tiene parámetros para especificar el precio de salida de la posición de liquidación. Esta función se utiliza principalmente para la liquidación inmediata a los precios actuales del mercado.


4、strategy.exit

strategy.exitLa función se utiliza para la operación de posición cerrada de entrada en la posición, a diferencia de la funciónstrategy.closeystrategy.close_allLa función es la liquidación inmediata al precio de mercado actual.strategy.exitLa función planea la liquidación de acuerdo con la configuración de los parámetros.

parámetro:

  • id: ID de pedido para la lista de condiciones de esta posición.
  • from_entry: ID de entrada que se utiliza para especificar la operación de liquidación que se realizará.
  • qtyLa cantidad de liquidaciones.
  • qty_percentPorcentaje de liquidez, rango: 0 ~ 100 ◦
  • profitEl objetivo de ganancias, expresado en puntos.
  • lossEl objetivo de la suspensión de daños, expresado en puntos.
  • limitLos objetivos de ganancias se determinan por el precio.
  • stopEl objetivo es detener el daño y fijar el precio.
  • whenCondiciones de ejecución:

Utiliza una estrategia de prueba para comprender el uso de los parámetros.

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"}] 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语言模板参数上「定价货币精度」参数设置有关

Utilizando la prueba de retroalimentación del modelo de precios en tiempo real, esta estrategia de prueba comienza a realizar 3 operaciones de entrada:strategy.entryFunción), el valor de long1 se ha configurado de forma deliberadalimitParámetros, el precio del listado es de 1 lo que hace que no se pueda negociar. Luego prueba la función de salida de la condiciónstrategy.exitSe utilizan paradas por número de puntos, paradas por precio, paradas por cantidad fija de posiciones, paradas por porcentaje. Dado que en el ejemplo de extensión solo se muestran paradas. La operación de parada de pérdidas también es equivalente.strategy.exitLa función también tiene parámetros de trazabilidad más complejos:trail_pricetrail_pointstrail_offsetTambién se puede probar su uso en este ejemplo.


5、strategy.cancel

strategy.cancelFunciones para cancelar/desactivar todos los comandos de la lista de preenlaces. Estas funcionesstrategy.order, strategy.entry , strategy.exitPuede generar ID de entrada. Los principales parámetros de la función son:idwhen

parámetro:

  • idLa identificación de la entrada que se quiere cancelar.
  • whenCondiciones de ejecución:

Esta función es muy bien entendida y se utiliza para cancelar órdenes de entrada que no se han realizado.

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, 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_allFunciones ystrategy.cancelFunciones similares a . cancelar / inhabilitar todos los comandos de la lista de preinstalación . Se puede especificarwhenParámetros

parámetro:

  • whenCondiciones de ejecución:
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, 0.2, limit=2) strategy.entry("long3", strategy.long, 0.3, limit=3) if not barstate.ishistory and close < open strategy.cancel_all() isStop := true

7、strategy.order

strategy.orderLas funciones de la función, la configuración de los parámetros, etc.strategy.entryConformidad, distingue entrestrategy.orderLa función no está protegida.strategyLa función depyramidingLa configuración de los parámetros tiene un efecto, no hay límite en el número de secuencias.

parámetro:

  • id: puede entenderse como un nombre que se utiliza para referirse a una posición de negociación. Puede referirse a este id para revocar, modificar órdenes, cerrar posiciones.
  • directionSi la dirección de la orden es hacer más (comprar) este parámetro se transmitestrategy.longEsta variable interna se transmite si se va a hacer un descuento.strategy.shortEsta variable es:
  • qty: Especifica la cantidad de pedidos, si no se transmite este parámetro, se usa la cantidad de pedidos por defecto.
  • when: condición de ejecución, se puede especificar este parámetro para controlar si se activa la operación de la orden actual.
  • limitEspecificar el precio de la orden.
  • stopEl precio de parada es:

Y lo usamos.strategy.orderNo hay restricciones en el número de secuencias de la función.strategy.exitLa función de salida condicional ❚ construir un guión de transacción similar a la red ❚ ejemplos muy sencillos, solo para aprender:

pine
/*backtest start: 2021-03-01 00:00:00 end: 2022-08-30 00:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Binance","currency":"ETH_USDT"}] args: [["ZPrecision",0,358374]] */ varip beginPrice = -1 if not barstate.ishistory if beginPrice == -1 or (math.abs(close - beginPrice) > 1000 and strategy.opentrades == 0) beginPrice := close for i = 0 to 20 strategy.order("buy"+i, strategy.long, 0.01, limit=beginPrice-i*200, when=(beginPrice-i*200)<close) strategy.exit("coverBuy"+i, "buy"+i, qty=0.01, profit=200) strategy.order("sell"+i, strategy.short, 0.01, limit=beginPrice+i*200, when=(beginPrice+i*200)>close) strategy.exit("coverSell"+i, "sell"+i, qty=0.01, profit=200)

Ejemplos de estrategia

Los ejemplos de estrategias en este tutorial solo se usan para enseñar estrategias, guiar el diseño de estrategias e ideas, no para hacer ninguna orientación o recomendación comercial. Las estrategias de enseñanza no son prácticas.

Estrategias para el indicador de tendencias súper

pine
strategy("supertrend", overlay=true) [supertrend, direction] = ta.supertrend(input(5, "factor"), input.int(10, "atrPeriod")) plot(direction < 0 ? supertrend : na, "Up direction", color = color.green, style=plot.style_linebr) plot(direction > 0 ? supertrend : na, "Down direction", color = color.red, style=plot.style_linebr) if direction < 0 if supertrend > supertrend[2] strategy.entry("entry long", strategy.long) else if strategy.position_size < 0 strategy.close_all() else if direction > 0 if supertrend < supertrend[3] strategy.entry("entry short", strategy.short) else if strategy.position_size > 0 strategy.close_all()

La estrategia de seguimiento de tendencias en el lenguaje Pine es muy sencilla, aquí diseñamos una estrategia de seguimiento de tendencias simple con un indicador de tendencias súper. Vamos a analizar el código fuente de esta estrategia.

Primero el código de la estrategiastrategyLa función hace algunos ajustes simples:strategy("supertrend", overlay=true)En este caso, la estrategia es simplemente poner un título de estrategia en la barra de supertrend.overlayLos parámetros sontrueCuando diseñamos una estrategia de Pine o aprendemos un script de estrategia de Pine, lo primero que tenemos que ver es el diseño de los parámetros de la interfaz de la estrategia.inputfunción

[supertrend, direction] = ta.supertrend(input(5, "factor"), input.int(10, "atrPeriod"))

inputLas llamadas de funciones son usadas directamente comota.supertrendLos parámetros de la función indicador se usan para calcular el indicador de tendencia súper. De ellos:

  • input(5, "factor")
  • input.int(10, "atrPeriod")

Por defecto, la función establece dos controles de parámetros en la interfaz de políticas del lenguaje Pine, como se muestra a continuación:

img

Se puede ver que el valor por defecto en el control esinputFunciones yinputLa serie de funciones que tenemos aquí esinput.intLos dos primeros parámetros de la función (y también los explicamos en los capítulos anteriores) nos permiten configurar en la interfaz de la estrategiata.supertrendLa función de los parámetros de la función. La función de los indicadores de tendencia súper calcula un preciosupertrendy una dirección de datosdirectionY luego usarlo.plotDibujo de gráficos de función, tenga en cuenta que cuando se dibuja un gráfico, se dibuja en la dirección de los indicadores de tendencia súper, y solo se dibuja la dirección actual.directionPor lo tanto, la tendencia actual es a la baja.directionPor lo tanto, podemos ver que la tendencia actual es a la baja.plotLa función de dibujo de la hora de juzgardirectionEs mayor que y menor que 0.

El siguienteif ... else ifLa lógica es el juicio de la señal de transacción, cuando la expresióndirection < 0En la actualidad, el indicador de tendencia súper se utiliza para indicar en tiempo real que la situación actual está en una fase ascendente, en la que si los datos de precios en el indicador de tendencia súpersupertrendMás alto que el precio del indicador de tendencia súper en el BAR 2 hacia adelante (es decir,supertrend[2],还记得历史操作符引用某个变量历史数据吧Si hay una posición en ese momento, la llamada de la función de pedido inverso eliminará la posición anterior y luego abrirá la posición de acuerdo con la dirección de la operación actual.supertrend > supertrend[2]Las condiciones no se han cumplido, siempre que en este momentostrategy.position_size < 0El hecho de tener una posición vacante también puede desencadenarstrategy.close_all()Ejecución de la función, para hacer la posición llena.

direction > 0En la fase de la tendencia a la baja también es lo mismo, si hay varios titulares, todos se liquidarán y luego cumplirán con las condicionessupertrend < supertrend[3]Cuando se activa la señal de vacío, aquí es por qué se configura como[3]¿Qué pasa con los datos de los precios de los indicadores de tendencias súper en el BAR de la tercera base del número anterior? Tal vez sea intencional para los estrategas, ya que en algunos mercados, como el mercado de negociación de contratos, el riesgo de pérdida de valor es un poco mayor que el de riesgo adicional.

parata.supertrend¿Algunos de mis compañeros de clase están interesados en saber si la tendencia actual es ascendente o descendente?

De hecho, este indicador también se puede implementar en la forma de una función personalizada en el lenguaje Pine:

pine
pine_supertrend(factor, atrPeriod) => src = hl2 atr = ta.atr(atrPeriod) upperBand = src + factor * atr lowerBand = src - factor * atr prevLowerBand = nz(lowerBand[1]) prevUpperBand = nz(upperBand[1]) lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand int direction = na float superTrend = na prevSuperTrend = superTrend[1] if na(atr[1]) direction := 1 else if prevSuperTrend == prevUpperBand direction := close > upperBand ? -1 : 1 else direction := close < lowerBand ? 1 : -1 superTrend := direction == -1 ? lowerBand : upperBand [superTrend, direction]

Esta función es la función de la configuración yta.supertrendEl mismo algoritmo, y por supuesto, los mismos indicadores.
A partir de este algoritmo de funciones personalizadas, podemos ver que el indicador de tendencia súper integrado de Pine se calcula utilizandohl2Variables integradas: (el precio más alto, el precio más bajo se suman y luego se dividen por 2, es decir, el promedio del precio más alto y el precio más bajo), y luego se calcula el indicador ATR de un período determinado según el parámetroatrPeriod (la amplitud de onda). Luego se utiliza hl2 y ATR para construir el tren de arriba, el tren de abajo.

Actualizaciones basadas en triángulos en el códigolowerBandyupperBand

pine
lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand

lowerBand: línea descendente, para determinar si hay cambios en la tendencia ascendente. upperBand: línea ascendente, para determinar si hay cambios en la tendencia descendente.

pine
else if prevSuperTrend == prevUpperBand direction := close > upperBand ? -1 : 1 else direction := close < lowerBand ? 1 : -1

En este caso, si el precio de la super tendencia en la barra anterior esprevUpperBand, es decir, la línea ascendente, indica que la tendencia actual es a la baja.closeMás deupperBandEl precio se rompe y se considera que es el momento en que la tendencia cambia y se convierte en una tendencia alcista.directionLa variable de dirección está configurada como -1 (en la tendencia ascendente). De lo contrario, está configurada como 1 (en la tendencia descendente).if direction < 0Cuando se activa la condición de la señal, se hace más.direction > 0Cuando se activa la condición de señal, se vacía.

pine
superTrend := direction == -1 ? lowerBand : upperBand [superTrend, direction]

Por último, se elige el precio y la dirección de los datos de los indicadores de tendencias súper específicas según la dirección.

Estrategias de equilibrio dinámico

pine
/*backtest start: 2021-03-01 00:00:00 end: 2022-09-08 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Binance","currency":"ETH_USDT"}] args: [["v_input_1",4374],["v_input_2",3],["v_input_3",300],["ZPrecision",0,358374]] */ varip balance = input(50000, "balance") varip stocks = input(0, "stocks") maxDiffValue = input(1000, "maxDiffValue") if balance - close * stocks > maxDiffValue and not barstate.ishistory // more balance , open long tradeAmount = (balance - close * stocks) / 2 / close strategy.order("long", strategy.long, tradeAmount) balance := balance - tradeAmount * close stocks := stocks + tradeAmount runtime.log("balance:", balance, ", stocks:", stocks, ", tradeAmount:", tradeAmount) else if close * stocks - balance > maxDiffValue and not barstate.ishistory // more stocks , open short tradeAmount = (close * stocks - balance) / 2 / close strategy.order("short", strategy.short, tradeAmount) balance := balance + tradeAmount * close stocks := stocks - tradeAmount runtime.log("balance:", balance, ", stocks:", stocks, ", tradeAmount:", tradeAmount) plot(balance, title="balance value(quoteCurrency)", color=color.red) plot(stocks*close, title="stocks value(quoteCurrency)", color=color.blue)

img

img

Continuamos con algunos ejemplos de diseño de estrategias en la lengua Pine, esta vez vamos a ver una estrategia de equilibrio dinámico.BaseCurrency(variedad de la transacción) yQuoteCurrencyLa cantidad de (moneda de cálculo) siempre hace un tratamiento de equilibrio. El precio relativo de los activos aumenta, el valor de la tenencia en la cuenta aumenta, el cual se vende. Si el precio relativo de un determinado activo disminuye, el valor de la tenencia en la cuenta disminuye, se compra este activo. Esto es lo que se conoce como estrategia de equilibrio dinámico.

La desventaja de esta estrategia es que, como se muestra en el gráfico de retroalimentación de esta estrategia, la estrategia de fluctuación de pérdidas es más grande en las etapas de la gran tendencia de los precios. Por lo tanto, esta estrategia es buena para la estrategia de efectivo, y su uso en futuros requiere un buen control del riesgo.

En este artículo, vamos a ver el diseño de la estrategia:

Usamos un diseño simplificado para simular unabalance(es decir, el número de activos de la moneda de cuota) ystocks(es decir, la cantidad de activos de BaseCurrency) Información de equilibrio. No estamos leyendo la cantidad real de activos en la cuenta, sólo estamos usando el monto simulado para calcular la compra y venta adecuada.maxDiffValue, este parámetro es el criterio para el equilibrio.BaseCurrencyyQuoteCurrencyLa desviación es superior amaxDiffValueEn la actualidad, la economía de los países en desarrollo está en equilibrio, vendiendo activos de alto precio y comprando activos de bajo precio para volver a equilibrarlos.

La activación de la señal de negociación estratégica debe tener sentido en la etapa BAR en tiempo real, por lo que las condiciones de negociación estratégica se establecen en el juicio ifnot barstate.ishistoryEl precio de la leche en el país es de aproximadamente US$29.000 por gallona.balanceEl valor es superior astocksComprar en el momento del valor. En cambio, vender. Actualizar después de ejecutar la declaración de transacción.balanceystocksLa variable, y luego se dispara el siguiente equilibrio.

La información de la revisión de la estrategia anterior contiene el precio de la variedad al inicio de la revisión de la estrategia, el precio es de 1458, así que he configurado los parámetrosbalanceEs el número 47741458*3), configuración de los parámetrosstocksPara: 3. Mantener el activo en equilibrio al principio.

Las estrategias de supertendencias para seguir y detener las pérdidas

En el curso anterior hemos aprendidostrategy.exitLa función de salida de posición, en la que el seguimiento de la función de parada de pérdidas no tenemos ejemplos para explicar. Este ejemplo de diseño de la estrategia de la sección se utilizastrategy.exitLa función de seguimiento de stop loss para la optimización de una estrategia de tendencia súper.

Primero vamos a verstrategy.exitLa función de seguimiento de los parámetros de parada de pérdida:

1、trail_priceParámetros: La posición de la acción lógica de la parada de pérdida de seguimiento de la unidad de liquidación (en la posición especificada por el precio) es activada.
2、trail_offsetParámetros: la distancia entre el precio más alto (cuando se hace más) o el precio más bajo (cuando se hace más) después de ejecutar el seguimiento de la acción de parada de pérdida.
3、trail_pointsParámetros: el mismotrail_priceLos parámetros, sólo se especifican en el número de puntos de ventaja.

No importa si es difícil de entender, vamos a entender el aprendizaje a través de un escenario de retroalimentación estratégica, que en realidad es muy sencillo.

pine
/*backtest start: 2022-09-23 00:00:00 end: 2022-09-23 08:00:00 period: 1m basePeriod: 1m exchanges: [{"eid":"Binance","currency":"ETH_USDT"}] args: [["RunMode",1,358374],["ZPrecision",0,358374]] */ strategy("test", overlay = true) varip a = na varip highPrice = na varip isTrade = false varip offset = 30 if not barstate.ishistory and not isTrade strategy.entry("test 1", strategy.long, 1) strategy.exit("exit 1", "test 1", 1, trail_price=close+offset, trail_offset=offset) a := close + offset runtime.log("每点价格为:", syminfo.mintick, ",当前close:", close) isTrade := true if close > a and not barstate.ishistory highPrice := na(highPrice) ? close : highPrice highPrice := close > highPrice ? close : highPrice plot(a, "trail_price 触发线") plot(strategy.position_size>0 ? highPrice : na, "当前最高价") plot(strategy.position_size>0 ? highPrice-syminfo.mintick*offset : na, "移动止损触发线")

img

img

img

La estrategia comienza a ejecutarse con una entrada inmediata de múltiples cabezas y luego con la siguiente inmediatastrategy.exitLa orden de salida ((especifica el parámetro de parada de pérdidas de seguimiento), comienza a ejecutar la lógica de parada de pérdidas de seguimiento cuando el precio de movimiento sube más allá de la línea de desencadenamiento de trail_price, la línea de parada de pérdidas ((azul) comienza a seguir el ajuste de la dinámica de precios más alta, la posición de la línea azul es el precio en el que la parada de pérdidas dispara la posición de equilibrio, y finalmente, cuando el precio de movimiento cae por debajo de la línea azul, se dispara la posición de equilibrio.

Entonces usamos esta función para optimizar una estrategia de super tendencia, y solo asignamos una orden de entrada a la estrategia.strategy.exitEn la lista de salida, se puede agregar esta función de seguimiento y deterioro.

pine
if not barstate.ishistory and findOrderIdx("open") >= 0 and state == 1 trail_price := strategy.position_size > 0 ? close + offset : close - offset strategy.exit("exit", "open", 1, trail_price=trail_price, trail_offset=offset) runtime.log("每点价格为:", syminfo.mintick, ",当前close:", close, ",trail_price:", trail_price) state := 2 tradeBarIndex := bar_index

El código de estrategia completo:

pine
/*backtest start: 2022-05-01 00:00:00 end: 2022-09-27 00:00:00 period: 1d basePeriod: 5m exchanges: [{"eid":"Binance","currency":"ETH_USDT"}] args: [["RunMode",1,358374],["ZPrecision",0,358374]] */ varip trail_price = na varip offset = input(50, "offset") varip tradeBarIndex = 0 // 0 : idle , 1 current_open , 2 current_close varip state = 0 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 if strategy.position_size == 0 trail_price := na state := 0 [superTrendPrice, dir] = ta.supertrend(input(2, "atr系数"), input(20, "atr周期")) if ((dir[1] < 0 and dir[2] > 0) or (superTrendPrice[1] > superTrendPrice[2])) and state == 0 and tradeBarIndex != bar_index strategy.entry("open", strategy.long, 1) state := 1 else if ((dir[1] > 0 and dir[2] < 0) or (superTrendPrice[1] < superTrendPrice[2])) and state == 0 and tradeBarIndex != bar_index strategy.entry("open", strategy.short, 1) state := 1 // 反向信号,全平 if strategy.position_size > 0 and dir[2] < 0 and dir[1] > 0 strategy.cancel_all() strategy.close_all() runtime.log("趋势反转,多头全平") else if strategy.position_size < 0 and dir[2] > 0 and dir[1] < 0 strategy.cancel_all() strategy.close_all() runtime.log("趋势反转,空头全平") if not barstate.ishistory and findOrderIdx("open") >= 0 and state == 1 trail_price := strategy.position_size > 0 ? close + offset : close - offset strategy.exit("exit", "open", 1, trail_price=trail_price, trail_offset=offset) runtime.log("每点价格为:", syminfo.mintick, ",当前close:", close, ",trail_price:", trail_price) state := 2 tradeBarIndex := bar_index plot(superTrendPrice, "superTrendPrice", color=dir>0 ? color.red : color.green, overlay=true)
Related Recommendations
Comment
All comments (0)
No data
No data
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)