[TOC] Je vous en prie.
Vidéo tutoriel:https://www.youtube.com/watch?v=CA3SwJQb_1g
FMZ Quant Trading Platform prend en charge la rédaction de stratégies en langage Pine, le backtesting et le trading en direct de stratégies en langage Pine, et il est compatible avec des versions inférieures de langage Pine.Place de la stratégiesur la plateforme de négociation quantitative FMZ (FMZ.COM).
FMZ prend en charge non seulement le langage Pine, mais aussi la puissante fonction de dessin du langage Pine. Les différentes fonctions, les outils riches et pratiques, la gestion efficace et pratique sur la plate-forme FMZ améliorent encore la faisabilité de la stratégie (script) Pine. Sur la base de la compatibilité avec le langage Pine, FMZ élargit, optimise et aménage également le langage Pine dans une certaine mesure. Avant d'entrer officiellement dans le tutoriel, jetons un coup d'œil aux changements apportés au langage Pine sur FMZ par rapport à la version originale.
Un bref aperçu de certaines des différences évidentes:
//@version
et lestrategy
, indicator
les déclarations au début du code ne sont pas obligatoires à écrire, FMZ ne prend pas en chargeimport
à importerlibrary
fonctionne pour le moment.On peut voir que certaines stratégies sont écrites comme ceci:
//@version=5
indicator("My Script", overlay = true)
src = close
a = ta.sma(src, 5)
b = ta.sma(src, 50)
c = ta.cross(a, b)
plot(a, color = color.blue)
plot(b, color = color.black)
plotshape(c, color = color.red)
Ou écrivez-le comme ceci:
//@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)
Sur FMZ, il peut être simplifié en:
src = close
a = ta.sma(src, 5)
b = ta.sma(src, 50)
c = ta.cross(a, b)
plot(a, color = color.blue, overlay=true)
plot(b, color = color.black, overlay=true)
plotshape(c, color = color.red, overlay=true)
Ou bien:
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)
Modèle de prix de clôture et modèle de prix en temps réel
En vue de la négociation, nous pouvons utiliser lecalc_on_every_tick
paramètre dustrategy
fonction de définir le script de stratégie pour exécuter la logique de la stratégie en temps réel lorsque le prix change à chaque fois.calc_on_every_tick
le paramètre doit être réglé surtrue
Lecalc_on_every_tick
le paramètre par défaut estfalse
, c'est-à-dire que la logique de stratégie n'est exécutée que lorsque la ligne K actuelle BAR de la stratégie est complètement terminée.
Sur FMZ, il est défini par les paramètres du modèle
Le contrôle de précision numérique, tel que le prix et le montant de la commande lors de l'exécution de la stratégie, doit être spécifié sur FMZ Dans la vue de la négociation, il n'y a pas de problème de précision lors du placement d'ordres de négociation réels, car il ne peut être testé que dans la simulation. Sur FMZ, il est possible d'exécuter la stratégie Pine dans le commerce réel. Ensuite, la stratégie doit être en mesure de spécifier la précision du prix et la précision du montant de l'ordre de la variété de négociation de manière flexible. Les paramètres de précision contrôlent le nombre de décimales dans les données pertinentes pour empêcher les données de ne pas répondre aux exigences de l'ordre de l'échange et donc de ne pas passer une commande.
Code du contrat à terme
Si le produit de trading sur FMZ est un contrat, il a deux attributs, ils sont respectivement swap
Par exemple, certaines bourses ont des contrats trimestriels.quarter
Ces codes de contrats sont compatibles avec les codes de contrats à terme définis dans le document de l'API du langage Javascript/python/c++ de FMZ.
Pour d'autres paramètres, tels que le montant minimum de l'ordre, le montant par défaut de l'ordre, etc., veuillez consulter l'introduction du paramètre sur
runtime.debug
, runtime.log
, runtime.error
utilisé pour le débogage.3 fonctions ont été ajoutées à la plateforme FMZ pour le débogage.
runtime.debug
: Imprimer des informations sur les variables sur la console, qui n'est généralement pas utilisée avec cette fonction.
runtime.log
Les fonctions spécifiques à la langue PINE sur FMZ.
runtime.log(1, 2, 3, close, high, ...), Multiple parameters can be passed.
runtime.error
: Il en résultera une erreur d'exécution avec le message d'erreur spécifié dans le paramètre de message lors de l'appel.
runtime.error(message)
overlay
paramètre est étendu dans certaines des fonctions de dessinDans le langage Pine sur FMZ, les fonctions de dessinplot
, plotshape
, plotchar
, etc. ont ajouté leoverlay
le support des paramètres, permettant de spécifier le dessin sur le graphique principal ou le sous-graphique.overlay
est réglée surtrue
pour dessiner sur le graphique principal, etfalse
est réglée pour tirer sur le sous-diagramme, ce qui permet à la stratégie Pine sur FMZ de tirer le diagramme principal et le sous-diagramme en même temps.
syminfo.mintick
variable intégréeLa variable intégréesyminfo.mintick
Cette valeur peut être contrôlée par la précision de la devise du paramètre modèle de tarification dans la bibliothèque de classes de négociation de langues de pins sur la FMZ.le robot/test de retourLe paramètre de précision de la devise de prix 2 signifie que le prix est précis à la seconde décimale lors de la négociation et que l'unité minimale de changement de prix est de 0,01.syminfo.mintick
est de 0,01.
Par exemple: le prix de commande est de 8000, la direction de vente, la quantité est de 1 lot (pièce, feuille), le prix moyen après la transaction n'est pas de 8000, mais inférieur à 8000 (le coût inclut les frais de manutention).
Lorsque vous commencez à apprendre les bases du langage Pine, il peut y avoir des exemples d'instructions et de grammaire de code que nous ne connaissons pas. Peu importe que vous ne le compreniez pas, nous pouvons d'abord nous familiariser avec les concepts et comprendre le but du test, ou vous pouvez consulter la documentation du langage Pine sur FMZ pour obtenir des instructions. Suivez ensuite le tutoriel étape par étape pour vous familiariser avec diverses grammaires, instructions, fonctions et variables intégrées.
Lorsque vous commencez à apprendre le langage Pine, il est très nécessaire de comprendre les concepts connexes tels que le processus d'exécution du programme de script de langage Pine. La stratégie de langage Pine fonctionne sur la base du graphique. On peut comprendre que la stratégie de langage Pine est une série de calculs et d'opérations, qui sont exécutés sur le graphique dans l'ordre des séries chronologiques à partir des données les plus anciennes qui ont été chargées sur le graphique. La quantité de données que le graphique charge initialement est limitée. Dans le trading réel, la quantité maximale de données est généralement déterminée en fonction du volume de données maximal renvoyé par l'interface d'échange, et la quantité maximale de données pendant le backtesting est déterminée en fonction des données fournies par la source de données du système de backtesting. La barre de ligne K la plus à gauche du graphique, c'est-à-dire le premier ensemble de données du graphique, a une valeur d'index de 0. La valeur de l'index de la barre de donnéesbar_index
dans la langue du pin.
plot(bar_index, "bar_index")
Leplot
fonction est l'une des fonctions que nous allons utiliser plus dans le futur. l'utilisation est très simple, il est de tracer une ligne sur le graphique selon les paramètres d'entrée, les données d'entrée estbar_index
, et la ligne est nomméebar_index
. On peut voir que la valeur de la ligne nommée bar_index sur la première barre est 0, et elle augmente de 1 à droite à mesure que la barre augmente.
Parce que les paramètres de la stratégie sont différents, les méthodes d'exécution du modèle de la stratégie sont différentes, elles peuvent être divisées enclosing price model
etreal-time price model
Nous avons également présenté brièvement les concepts d'entre eux avant.
Modèle de prix de clôture
Lorsque le code de stratégie est exécuté, la période de la barre de ligne K courante est complètement exécutée, et lorsque la ligne K est fermée, la période de ligne K a été complétée.
Modèle de prix en temps réel
Lorsque le code de stratégie est exécuté, indépendamment du fait que la barre de ligne K actuelle soit fermée ou non, la logique de stratégie Pine sera exécutée chaque fois que le marché change et le signal de trading déclenché sera exécuté immédiatement.
Lorsque la stratégie du langage Pine est exécutée de gauche à droite sur le graphique, les barres de ligne K sur le graphique sont divisées enHistorical Bars
etReal-time Bars
:
Bar historique
Lorsque la stratégie est réglée sur Historical Bars
La logique de stratégie n'est exécutée qu'une seule fois sur chaquehistorical bar
Je suis désolée.
Lorsque la stratégie est réglée sur historical bars
La logique de stratégie n'est exécutée qu'une seule fois sur chaquehistorical bar
.
Calcul basé sur les barres historiques: Le code de stratégie est exécuté une fois dans l'état de fermeture de la barre historique, puis le code de stratégie continue d'être exécuté dans la barre historique suivante jusqu'à ce que toutes les barres historiques soient exécutées une fois.
Barre en temps réel
Lorsque la stratégie est exécutée jusqu'à la dernière barre de ligne K à l'extrême droite, la barre est une barre en temps réel.
Lorsque la stratégie est définie sur
Calcul basé sur Bar en temps réel:
Si la stratégie est définie sur high
, low
, close
Ces valeurs peuvent changer à chaque fois que le marché change sur les barres en temps réel. Par conséquent, les données telles que les indicateurs calculés sur la base de ces valeurs changeront également en temps réel.close
représente toujours le dernier prix actuel, ethigh
etlow
représente toujours le point le plus élevé et le point le plus bas atteint depuis le début de la barre en temps réel en cours.
Mécanisme de rétroaction lors de l'exécution de stratégies sur Bar en temps réel (modèle de prix en temps réel): Lors de l'exécution en temps réel de Bar, la réinitialisation des variables définies par l'utilisateur avant chaque nouvelle itération de la stratégie est appelée rollback.
Attention!
/*backtest
...
..
.
*/
Le contenu du paquet est constitué des informations de configuration de backtest enregistrées sous forme de code sur la plateforme FMZ.
/*backtest
start: 2022-06-03 09:00:00
end: 2022-06-08 15:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/
var n = 0
if not barstate.ishistory
runtime.log("before n + 1, n:", n, " current bar_index:", bar_index)
n := n + 1
runtime.log("after n + 1, n:", n, " current bar_index:", bar_index)
plot(n, title="n")
Nous examinons seulement la scène exécutée pendant les bars en temps réel, donc nous utilisons lenot barstate.ishistory
expression pour limiter l'accumulation de la variable n uniquement dans la barre en temps réel, et utiliserruntime.log
fonction de sortie de l'information dans le journal de stratégie avant et après l'opération d'accumulation.plot
, on peut voir que n est toujours égal à 0 lorsque la stratégie est exécutée dans les Bars historiques. Lorsque la barre en temps réel est exécutée, l'opération d'addition de 1 à n est déclenchée, et l'opération d'addition de 1 à n est exécutée lorsque la stratégie est exécutée à chaque tour de la barre en temps réel. On peut observer à partir du message de journal que n sera réinitialisé à la valeur finalement soumise par la stratégie d'exécution de la barre précédente lorsque le code de stratégie est ré-exécuté à chaque tour. La mise à jour de la valeur n sera soumise lorsque le code de stratégie est exécuté sur la barre en temps réel pour la dernière fois, vous pouvez donc voir que la valeur de la courbe n augmente de 1 à chaque augmentation de Bar à partir de la barre en temps réel sur le graphique.
Résumé:
En raison du retour en arrière des données, les opérations de dessin, telles que les courbes sur le graphique, peuvent également entraîner un redessin.
var n = 0
if not barstate.ishistory
runtime.log("before n + 1, n:", n, " current bar_index:", bar_index)
n := open > close ? n + 1 : n
runtime.log("after n + 1, n:", n, " current bar_index:", bar_index)
plot(n, title="n")
Capture d'écran du temps A
Capture d'écran du temps B
On a seulement modifié la phrase:n := open > close ? n + 1 : n
, il suffit d'ajouter 1 à n lorsque la barre en temps réel actuelle est une ligne négative (c'est-à-dire que le prix d'ouverture est supérieur au prix de clôture). On peut voir que dans le premier graphique (temps A), puisque le prix d'ouverture était supérieur au prix de clôture (ligne négative) à ce moment-là, n a été accumulé de 1, et la valeur de n affichée sur la courbe du graphique était de 5. Ensuite, le marché a changé et le prix a été mis à jour comme indiqué dans le deuxième graphique (temps B). À ce moment-là, le prix d'ouverture est inférieur au prix de clôture (ligne positive), et la valeur de n retombe sans augmentation de 1.
Contextes variables dans les fonctions
Étudions ensemble les variables de la fonction de langage Pine. Selon certaines descriptions sur les tutoriels Pine, les variables de la fonction ont les différences suivantes par rapport aux variables en dehors de la fonction:
L'historique des variables de série utilisées dans la fonction Pine est créé à chaque appel successif à la fonction. Si la fonction n'est pas appelée sur chaque barre sur laquelle le script s'exécute, cela entraînera une divergence entre les valeurs historiques de la série à l'intérieur et à l'extérieur du bloc local de la fonction. Par conséquent, si la fonction n'est pas appelée sur chaque barre, la série référencée à l'intérieur et à l'extérieur de la fonction avec la même valeur d'index ne fera pas référence au même point historique.
C'est un peu difficile à comprendre? On va le trouver avec un code de test qui fonctionne sur FMZ:
/*backtest
start: 2022-06-03 09:00:00
end: 2022-06-08 15:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/
f(a) => a[1]
f2() => close[1]
oneBarInTwo = bar_index % 2 == 0
plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A")
plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
plot(close[2], title = "close[2]", color = color.red, overlay = true)
plot(close[1], title = "close[1]", color = color.green, overlay = true)
Capture d'écran de l'exécution du backtest
Le code d'essai est relativement simple, principalement pour examiner les données référencées par deux méthodes:f(a) => a[1]
etf2() => close[1]
.
f(a) => a[1]
: Utiliser la méthode de transmission des paramètres, la fonction renvoie àa[1]
finally.
f2() => close[1]
: Utiliser la variable intégréeclose
directement, et la fonction retourne àclose[1]
finally.
Le[]
Le symbole est utilisé pour faire référence à la valeur historique de la variable de la série de données, et close[1] fait référence aux données de prix de clôture sur la barre avant le prix de clôture actuel. Notre code de test dessine un total de 4 types de données sur le graphique:
plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A")
Dessinez un caractère f(close)
.
plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
Dessinez un caractère f2()
.
plot(close[2], title = "close[2]", color = color.red, overlay = true)
Tracez une ligne, la couleur est rouge, et la position dessinée (sur l'axe Y) est:close[2]
, qui est le prix de clôture de la deuxième barre avant la barre courante (comptant 2 barres à gauche).
plot(close[1], title = "close[1]", color = color.green, overlay = true)
Tracez une ligne, la couleur est verte, et la position dessinée (sur l'axe Y) est:close[1]
, qui est le prix de clôture de la première barre avant la barre courante (en comptant 1 barre à gauche).
Il peut être vu à partir de la capture d'écran de la stratégie backtesting que bien que les deux fonctionf(a) => a[1]
utilisé pour dessiner le marqueur A et la fonctionf2() => close[1]
utilisé pour dessiner le marqueur B [1] pour faire référence aux données historiques sur la série de données, les positions du marqueur plot(close[2], title = "close[2]", color = color.red, overlay = true)
, les données utilisées pour tracer la ligne sontclose[2]
.
La raison est de calculer si de tracer les marqueurs bar_index
. Les marqueurs f(a) => a[1]
ne sera pas la même que la valeur référencée par la fonctionf2() => close[1]
si la fonction n'est pas appelée sur chaque barre (même si les deux utilisent le même index comme [1]).
Certaines fonctions intégrées doivent être calculées sur chaque barre afin de calculer leurs résultats correctement
Pour illustrer cette situation avec un exemple simple:
res = close > close[1] ? ta.barssince(close < close[1]) : -1
plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)
Nous écrivons le code d'appel de la fonctionta.barssince(close < close[1])
dans un opérateur ternairecondition ? value1 : value2
. Cela provoque l'appel de la fonction ta.barssince uniquement lorsqueclose > close[1]
Mais leta.barssince
fonction est de calculer le nombre de lignes K depuis la dernière foisclose < close[1]
Lorsque la fonction ta.barssince est appelée, elle est toujours close > close[1], c'est-à-dire que le prix de clôture actuel est supérieur au prix de clôture de la barre précédente.
ta.barssince: Lorsqu'elle est appelée, la fonction renvoie na si la condition n'a jamais été remplie avant la ligne K actuelle.
Comme le montre le tableau:
Donc, lorsque le graphique est dessiné, seules les données avec une valeur pour la variable res (-1) sont dessinées.
Pour éviter ce problème, nous prenons simplement leta.barssince(close < close[1])
la fonction appelle l'opérateur ternaire et l'écrit à l'extérieur de toutes les branches conditionnelles possibles, ce qui lui permet d'effectuer des calculs sur chaque K-line Bar.
a = ta.barssince(close < close[1])
res = close > close[1] ? a : -1
plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)
Le concept de série temporelle est très important dans le langage Pine, et c'est un concept que nous devons comprendre lorsque nous apprenons le langage Pine. La série temporelle n'est pas un type mais une structure de base pour stocker des valeurs continues de variables au fil du temps. Nous savons que les scripts Pine sont basés sur des graphiques, et le contenu le plus basique affiché dans le graphique est le graphique en ligne K.open
est une variable intégrée du langage Pine, et sa structure est de stocker la série temporelle du prix d'ouverture de chaque K-line Bar.open
représente les prix d'ouverture de toutes les barres de ligne K de la première barre au début du graphique de ligne K actuel à la barre où le script actuel est exécuté.open
dans le code de stratégie Pine, c'est le prix d'ouverture de la barre de la ligne K lorsque le code de stratégie est actuellement exécuté.[]
Lorsque la stratégie Pine est exécutée sur une certaine K-line Bar, utiliseropen[1]
pour faire référence au prix d'ouverture de la barre de ligne K précédente (c'est-à-dire le prix d'ouverture de la période de ligne K précédente) qui fait référence auopen
série temporelle sur laquelle cette barre de lignes K est actuellement exécutée par le script.
Les variables sur les séries temporelles sont très pratiques pour l'informatique
Prenons la fonction intégréeta.cum
à titre d'exemple:
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
Code de test:
v1 = 1
v2 = ta.cum(v1)
plot(v1, title="v1")
plot(v2, title="v2")
plot(bar_index+1, title="bar_index")
Il y a beaucoup de fonctions intégrées commeta.cum
qui peut traiter les données sur les séries temporelles directement.ta.cum
est l'accumulation des valeurs correspondant aux variables transmises sur chaque K-line Bar, et ensuite nous utilisons un graphique pour le rendre plus facile à comprendre.
Processus de mise en œuvre de la stratégie | Variable intégrée bar_index | v1 | V2 |
---|---|---|---|
La stratégie fonctionne sur la première barre de la ligne K. | 0 | 1 | 1 |
La stratégie fonctionne sur la deuxième barre de la ligne K. | 1 | 1 | 2 |
La stratégie fonctionne sur la troisième barre de la ligne K. | 2 | 1 | 3 |
… | … | … | … |
La stratégie s'exécute sur la barre de ligne K N + 1 | N | 1 | N+1 |
On peut voir que v1, v2 et même bar_index sont toutes des structures de séries temporelles, et il y a des données correspondantes sur chaque barre.
Parce que la variable v1 est 1 sur chaque Bar, lorsque leta.cum(v1)
fonction est exécutée sur la première ligne K Bar, il n'y a que la première Bar, donc le résultat du calcul est 1 et attribué à la variable v2.
Quand?ta.cum(v1)
est exécuté sur la deuxième K-line Bar, il y a déjà 2 K-line Bars (la variable intégrée bar_index correspondant à la première est 0, et la seconde correspondant à la variable intégrée bar_index est 1), donc le résultat du calcul est 2, qui est attribué à la variable v2, et ainsi de suite.bar_index
est augmenté de 0, alorsbar_index + 1
sur le graphique, on peut aussi voir que les lignesv2
etbar_index
Ils se chevauchent en effet.
De même, je peux également utiliser leta.cum
La fonction intégrée pour calculer la somme des prix de clôture pour toutes les barres sur le graphique actuel.ta.cum(close)
, Lorsque la stratégie s'exécute à la barre en temps réel à l'extrême droite, le résultat calculé parta.cum(close)
est la somme des prix de clôture de toutes les barres du graphique (s'il n'est pas à l'extrême droite, il ne s'accumule que jusqu'à la barre actuelle).
Les variables des séries chronologiques peuvent également être calculées à l'aide d'opérateurs, tels que le code:ta.sma(high - low, 14)
, soustraire la variable intégréehigh
(le prix le plus élevé de la barre de la ligne K)low
(le prix le plus bas de K-line Bar), et enfin utiliser leta.sma
fonction pour calculer la valeur moyenne.
Le résultat d'un appel de fonction laissera également des traces de valeurs dans la série temporelle.
v1 = ta.highest(high, 10)[1]
v2 = ta.highest(high[1], 10)
plot(v1, title="v1", overlay=true)
plot(v2, title="v2", overlay=true)
Le code de test s'exécute pendant le backtesting, et on peut observer que les valeurs dev1
etv2
Le résultat calculé par l'appel de la fonction laissera des traces de la valeur dans la série chronologique, comme leta.highest(high, 10)
dans le codeta.highest(high, 10)[1]
Le résultat calculé par l'appel de la fonction peut également utiliser [1] pour faire référence à sa valeur historique.ta.highest(high, 10)
correspondant à la barre précédente de la barre actuelle, le résultat du calcul estta.highest(high[1], 10)
Alors...ta.highest(high[1], 10)
etta.highest(high, 10)[1]
sont exactement équivalents.
Utiliser une autre fonction de dessin pour produire la vérification des informations:
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)
Nous pouvons voir que les valeurs de la variable a et de la variable b dans la série temporelle sont affichées au-dessus et en dessous des Bars correspondantes. Nous pouvons conserver ce code de dessin pendant le processus d'apprentissage, car nous pouvons souvent avoir besoin de produire des informations sur le graphique pour l'observation pendant les tests et l'expérimentation.
Dans la première partie du tutoriel, nous avons résumé certaines différences dans l'utilisation du langage Pine sur FMZ et Trading View.indicator()
, strategy()
, etlibrary()
Bien sûr, afin d'être compatible avec les versions antérieures des scripts Pine, des stratégies telles que://@version=5
, indicator()
, strategy()
Certains paramètres de stratégie peuvent également être définis en passant des paramètres dans lestrategy()
function.
<version>
<declaration_statement>
<code>
Le<version>
Les informations relatives au contrôle de version peuvent être omises.
La langue du pin utilise//
comme symbole de commentaire d'une seule ligne, puisque la langue Pine n'a pas de symbole de commentaire de plusieurs lignes. FMZ étend le symbole de commentaire/**/
pour les commentaires de plusieurs lignes.
Les lignes du script qui ne sont pas des commentaires ou des directives du compilateur sont des instructions, qui mettent en œuvre l'algorithme du script.
if
, for
, while
ouswitch
la structureLes déclarations peuvent être organisées de différentes manières.
space
Les lignes commençant à la première position, par définition, font partie de la portée globale du script.local block
Un bloc local doit être indenté par un onglet ou quatre espaces (sinon, il sera analysé comme le code concaténé de la ligne précédente, c'est-à-dire jugé comme le contenu continu de la ligne précédente de code), et chaque bloc local définit une portée locale différente.Par exemple, il comprend trois blocs locaux, un dans la déclaration de fonction personnalisée et deux dans la déclaration de variable en utilisant la structure if, comme suit:
indicator("", "", true) // declaration statement (global scope), can be omitted
barIsUp() => // function declaration (global scope)
close > open // local block (local scope)
plotColor = if barIsUp() // variable declaration (global scope)
color.green // local block (local scope)
else
color.red // local block (local scope)
runtime.log("color", color = plotColor) // Call a built-in function to output the log (global scope)
Les lignes longues peuvent être divisées en plusieurs lignes, ou enveloppées. Une ligne enveloppée doit être indentée par n'importe quel nombre d'espaces, tant qu'elle n'est pas un multiple de 4 (ces limites sont utilisées pour indenter des blocs locaux).
a = open + high + low + close
Il peut être emballé comme suit (notez que le nombre d'espaces en retrait par ligne ne peut pas être un multiple de 4):
a = open +
high +
low +
close
Un appel long peut être décrit comme suit:
close1 = request.security(syminfo.tickerid, "D", close) // syminfo.tickerid daily level closing price data series for the current trading pair
close2 = request.security(syminfo.tickerid, "240", close) // syminfo.tickerid 240-minute level closing price data series for the current trading pair
plot(ta.correlation(close, open, 100), // line-long plot() calls can be wrapped
color = color.new(color.purple, 40),
style = plot.style_area,
trackprice = true)
Cependant, comme un bloc local doit commencer par une indentation en grammaire (4 espaces ou 1 onglet), lors de sa division sur la ligne suivante, la continuation d'une instruction doit commencer par plus d'une indentation (pas égale à 4 multiples d'espaces).
test(c, o) =>
ret = c > o ?
(c > o+5000 ?
1 :
0):
(c < o-5000 ?
-1 :
0)
a = test(close, open)
plot(a, title="a")
Avant de reconnaître les variables, nous devons d'abord comprendre le concept de
(A-Z)
ou en minuscules(a-z)
lettre ou soulignement(_)
comme premier caractère du marqueur.Par exemple, les marqueurs nommés suivants:
fmzVar
_fmzVar
fmz666Var
funcName
MAX_LEN
max_len
maxLen
3barsDown // Wrong naming! It used a numeric character as the leading character of the marker
Comme la plupart des langages de programmation, le langage Pine a également des suggestions d'écriture.
// name variables, constants
GREEN_COLOR = #4CAF50
MAX_LOOKBACK = 100
int fastLength = 7
// name functions
zeroOne(boolValue) => boolValue ? 1 : 0
Les opérateurs sont des symboles d'opération utilisés dans les langages de programmation pour construire des expressions, et les expressions sont des règles de calcul conçues pour certains objectifs de calcul lorsque nous écrivons des stratégies.
opérateurs d'affectation, opérateurs arithmétiques, opérateurs de comparaison, opérateurs logiques,? :
les opérateurs ternaires,[]
les opérateurs de référence historiques.
Prendre l'opérateur arithmétique*
par exemple, il est différent du problème de type causé par le résultat de retour de l'opérateur de la langue Pine sur Trading View.
//@version=5
indicator("")
lenInput = input.int(14, "Length")
factor = year > 2020 ? 3 : 1
adjustedLength = lenInput * factor
ma = ta.ema(close, adjustedLength) // Compilation error!
plot(ma)
Lorsque vous exécutez ce script sur Trading View, une erreur de compilation se produira.adjustedLength = lenInput * factor
, le résultat estseries int
type (série), mais le deuxième paramètre de la fonctionta.ema
Mais il n'y a pas de restrictions aussi strictes sur FMZ, le code ci-dessus peut fonctionner normalement.
Examinons ensemble l'utilisation de différents opérateurs.
Il existe 2 types d'opérateurs d'affectation:=
, :=
, que nous avons vu dans plusieurs exemples au début du tutoriel.
Le=
L'opérateur est utilisé pour attribuer une valeur à une variable lorsqu'elle est initialisée ou déclarée.=
Il s'agit de déclarations de variables valides:
a = close // Use built-in variables to assign values to a
b = 10000 // Use numerical assignment
c = "test" // Use string assignment
d = color.green // Use color value assignment
plot(a, title="a")
plot(b, title="b")
plotchar(true, title="c", char=str.tostring(c), color=d, overlay=true)
Notez que l'énoncé de missiona = close
, la variable a sur chaque barre est le prix de clôture (close) actuel de la barre.b
, c
, d
sont inchangés et peuvent être testés dans le système de backtest sur FMZ et les résultats sont visibles sur le graphique.
:=
On peut comprendre simplement que la valeur de la variable est la valeur de l'indicateur.:=
L'opérateur est utilisé pour modifier les valeurs des variables qui ont été déclarées et initialisées.
Si nous utilisons le:=
l'opérateur pour attribuer une valeur à une variable non initialisée ou déclarée, il provoquera une erreur, par exemple:
a := 0
Par conséquent, le:=
l'opérateur d'attribution est généralement utilisé pour réattribuer des variables existantes, par exemple:
a = close > open
b = 0
if a
b := b + 1
plot(b)
Jugez siclose > open
(c'est-à-dire que le BAR actuel est une ligne positive), la variable a est vraie. Le code dans le bloc local de l'instruction ifb := b + 1
est exécuté, et l'opérateur d'affectation:=
Ensuite, nous utilisons la fonction graphique pour dessiner la valeur de la variable b sur chaque BAR de la série temporelle sur le graphique, et les connecter en une ligne.
Est-ce que nous pensons que quand une ligne positive BAR apparaît, b continuera à s'accumuler de 1? Bien sûr que non, ici nous déclarons et initialisons la variable b comme 0 sans utiliser de désignation de mot clé.b=0
est exécuté sur chaque BAR, donc nous pouvons voir que le résultat de ce code est de réinitialiser la variable b à 0 à chaque fois, si la variable a est vraie, c'est-à-dire en ligne avecclose > open
, alors b sera augmenté de 1 lorsque le code est exécuté dans ce round, et b est 1 lorsque la fonction de tracé dessine, mais b est réaffecté à 0 lorsque le code est exécuté dans le round suivant. C'est aussi l'endroit où les débutants de la langue Pine sont sujets aux pièges.
En ce qui concerne les opérateurs d'affectation, nous devons développer sur deux mots clés:var
, varip
- Je ne sais pas.
En fait, nous avons vu et utilisé ce mot clé dans les tutoriels précédents, mais nous ne l'avons pas discuté en détail à ce moment-là.
var est un mot-clé utilisé pour l'allocation et l'initialisation ponctuelle de variables. En général, la grammaire de l'attribution de variables qui ne contient pas le mot-clé var provoque la valeur de la variable
s à être écrasée à chaque fois que les données sont mises à jour. En revanche, lorsque les variables sont affectées en utilisant le mot-clé var, elles peuvent maintenir l'état malgré les mises à jour de données.
Nous utilisons toujours cet exemple, mais nous utilisons levar
mot clé lors de l'attribution d'une valeur à b ici.
a = close > open
var b = 0
if a
b := b + 1
plot(b)
Levar
mot clé permet à la variable b d'effectuer l'affectation initiale seulement, et alors il ne réinitialisera pas b à 0 à chaque fois que la logique de stratégie est exécutée, de sorte qu'il peut être observé à partir de la ligne dessinée à l'exécution que b est le nombre de lignes positives BARs qui sont apparus lorsque la ligne actuelle K BAR a été backtesté.
Les variables déclarées par var peuvent être écrites non seulement dans la portée globale, mais aussi dans des blocs de code, comme dans cet exemple:
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
variété
Nous voyons le mot clévarip
Pour la première fois, nous pouvons regarder la description de ce mot clé:
varip (var intrabar persist) est un mot-clé pour l'attribution et l'initialisation unique de variables. Il est similaire au mot-clé var, mais les variables déclarées avec varip conservent leurs valeurs lors des mises à jour en temps réel de la ligne K.
Est-ce difficile à comprendre? Peu importe, nous l'expliquons par un exemple, c'est facile à comprendre.
strategy(overlay=true)
// test var varip
var i = 0
varip ii = 0
// Print the i and ii changed in each round of the strategy logic on the chart
plotchar(true, title="ii", char=str.tostring(ii), location=location.abovebar, color=color.red)
plotchar(true, title="i", char=str.tostring(i), location=location.belowbar, color=color.green)
// Increment i and ii by 1 for each round of logic execution
i := i + 1
ii := ii + 1
Ce code de test a des performances différentes sur le modèle
Modèle de barre:
Vous souvenez-vous que l'exécution de la stratégie que nous avons expliqué plus tôt est divisé en étape BAR historique et en temps réel BAR étape?i
, ii
déclaré envar
, varip
effectuer des opérations incrémentielles à chaque tour d'exécution du code de stratégie. Par conséquent, on peut voir que les nombres affichés sur la ligne K BAR du résultat du backtest sont augmentés de 1 un par un. Lorsque l'étape historique de la ligne K se termine, l'étape de la ligne K en temps réel commence. Les variables déclarées par var et varip commencent à subir des changements différents. Parce que c'est un modèle de barre, le code de stratégie sera exécuté une fois pour chaque changement de prix dans une ligne K BAR,i := i + 1
etii := ii + 1
La différence est que ii est modifié à chaque fois. Bien que i soit modifié à chaque fois, la valeur précédente sera restaurée lorsque la logique de stratégie est exécutée dans le tour suivant (rappelez-vous le mécanisme de retour que nous avons expliqué dans le chapitre précédent
Modèle de tique: Puisque le modèle Tick n'exécute la logique de stratégie qu'une seule fois par K-line BAR. Ainsi, dans le modèle de prix de clôture, les variables déclarées par var et varip se comportent exactement de la même manière dans l'exemple ci-dessus en augmentant de 1 pour chaque K-line BAR pendant l'étape historique de la ligne K et l'étape de la ligne K en temps réel.
Les opérateurs | Définition |
---|---|
+ | Ajout |
- | Soustraction |
* | Multiplication |
/ | La division |
% | Moduleur |
Le+
et-
Les autres opérateurs arithmétiques ne peuvent être utilisés que comme opérateurs binaires et il signalera une erreur s'il a été utilisé comme opérateur unitaire.
+
, le résultat du calcul est une chaîne, la valeur sera convertie en forme de chaîne, puis les chaînes sont cousues ensemble.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
Le langage Pine sur FMZ est un peu différent du langage Pine sur Trading View, le langage Pine sur FMZ n'est pas très strict sur les types de variables.
a = 1 * "1.1"
b = "1" / "1.1"
c = 5 % "A"
plot(a)
plot(b)
plot(c)
Il fonctionne sur FMZ, mais il signale une erreur de type sur la vue de trading. Si les deux opérandes de l'opérateur arithmétique sont des chaînes, le système convertit les chaînes en valeurs numériques et les calcule ensuite. Si une chaîne non numérique ne peut pas être calculée, le résultat de l'opération du système est une valeur nulle
Les opérateurs de comparaison sont tous des opérateurs binaires.
Les opérateurs | Définition |
---|---|
< | < |
> | > |
<= | <= |
>= | >= |
== | == |
!= | != |
Exemple de test:
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
Comme nous pouvons le voir, l'opérateur de comparaison est très simple à utiliser, mais c'est aussi l'opérateur que nous utilisons le plus lorsque nous écrivons des stratégies.close
, open
, etc.
Comme pour l'opérateur, il existe une différence sur le langage Pine entre FMZ et Trading View.d = "1" >= 2
ne signalera pas d'erreur sur FMZ, et il sera exécuté en convertissant d'abord la chaîne en une valeur, puis en comparant l'opération.
Les opérateurs | Symboles de code | Définition |
---|---|---|
Je ne sais pas. | Je ne sais pas. | Opérateur unarien, pas opérations |
et | et | Opérateurs binaires et opérations |
ou | ou | Opérateurs binaires ou opérations |
Quand il s'agit d'opérateurs logiques, alors nous devons parler de tables de vraies valeurs.
a = 1 == 1 // An expression formed by using comparison operators, the result is a Boolean value
b = 1 != 1
c = not b // Logical not operators
d = not a // Logical not operators
runtime.log("test the logical operator:and", "#FF0000")
runtime.log("a:", a, ", c:", c, ", a and c:", a and c)
runtime.log("a:", a, ", b:", b, ", a and b:", a and b)
runtime.log("b:", b, ", c:", c, ", b and c:", b and c)
runtime.log("d:", d, ", b:", b, ", d and b:", d and b)
runtime.log("test the logical operator:or", "#FF0000")
runtime.log("a:", a, ", c:", c, ", a or c:", a or c)
runtime.log("a:", a, ", b:", b, ", a or b:", a or b)
runtime.log("b:", b, ", c:", c, ", b or c:", b or c)
runtime.log("d:", d, ", b:", b, ", d or b:", d or b)
runtime.error("stop")
Afin de ne pas surimpression des messages, nous jetons une erreur avec leruntime.error("stop")
Après cela, nous pouvons observer les informations de sortie, et nous pouvons trouver que le contenu imprimé est en fait le même que la table de valeur réelle.
Expressions ternaires utilisant l'opérateur ternaire? :
combiné avec des opérandescondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
Nous les avons également utilisés dans les leçons précédentes. l'expression dite ternaire, opérateur ternaire signifie qu'il y a trois opérandes en elle.
Dans lecondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
, condition
est la condition de jugement. Si elle est vraie, la valeur de l'expression est:valueWhenConditionIsTrue
Si.condition
est false, alors la valeur de l'expression estvalueWhenConditionIsFalse
.
Exemple d'une démonstration pratique, bien que peu pratique:
a = close > open
b = a ? "positive line" : "negative line"
c = not a ? "negative line" : "positive line"
plotchar(a, location=location.abovebar, color=color.red, char=b, overlay=true)
plotchar(not a, location=location.belowbar, color=color.green, char=c, overlay=true)
Que faire si nous rencontrons un doji? Cela n'a pas d'importance! Les expressions ternaires peuvent également être imbriquées, comme nous l'avons fait dans le tutoriel précédent.
a = close > open
b = a ? math.abs(close-open) > 30 ? "positive line" : "doji" : math.abs(close-open) > 30 ? "negative line" : "doji"
c = not a ? math.abs(close-open) > 30 ? "negative line" : "doji" : math.abs(close-open) > 30 ? "positive line" : "doji"
plotchar(a, location=location.abovebar, color=color.red, char=b, overlay=true)
plotchar(not a, location=location.belowbar, color=color.green, char=c, overlay=true)
En fait, cela revient à remplacervalueWhenConditionIsTrue
etvalueWhenConditionIsFalse
danscondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
avec une autre expression ternaire.
Utiliser l'opérateur historique[]
Ces valeurs historiques sont les valeurs de la variable sur la barre de ligne K avant la barre de ligne K actuelle lorsque le script était en cours d'exécution.[]
L'opérateur est utilisé après les variables, les expressions et les appels de fonctions.[]
Par exemple, si je veux citer le prix de clôture du dernier K-line BAR, nous l'écrivons comme:close[1]
.
Nous avons vu quelque chose comme ça dans les leçons précédentes:
high[10]
ta.sma(close, 10)[1]
ta.highest(high, 10)[20]
close > nz(close[1], open)
Le[]
L'opérateur ne peut être utilisé qu'une seule fois sur la même valeur, il est donc erroné de l'écrire comme ceci, et une erreur sera signalée:
a = close[1][2] // error
Ici, on peut dire que l'opérateur[]
est utilisé pour la structure de série, il semble que la structure de série (série) est similaire à array!
Utilisons un exemple pour illustrer la différence entre les séries et les tableaux dans la langue Pine.
strategy("test", overlay=true)
a = close
b = close[1]
c = b[1]
plot(a, title="a")
plot(b, title="b")
plot(c, title="c")
a = close[1][2]
signalera une erreur, mais:
b = close[1]
c = b[1]
Mais si elle est écrite séparément, elle ne rapportera pas d'erreur.b = close [1]
, b devrait être une valeur, maisc = b[1]
, b peut encore être utilisé pour faire référence à la valeur historique à nouveau en utilisant l'opérateur historique. On peut voir que le concept de série dans le langage Pine n'est pas aussi simple qu'un tableau. Il peut être compris comme la valeur historique sur la dernière barre de close (assignée à b), b est également une structure de séries chronologiques (séries chronologiques), et son h