Type/to search
8
Follow
1364
Followers
Tutoriel d'introduction au langage quantitatif PINE d'Inventor
Tutorials
Created 2022-05-30 16:23:43  Updated 2022-09-28 17:10:21
 0
 12336

Tutoriel d'introduction au langage quantitatif PINE d'Inventor

Le tutoriel vidéo:
Comment faire pour entrer dans le commerce quantique?

La plate-forme de trading quantique de l'inventeur prend en charge les stratégies d'écriture du langage Pine, prend en charge les stratégies de retour de données et de fonctionnement en direct du langage Pine, et est compatible avec les versions inférieures du langage Pine.Place de la stratégieIl y a beaucoup de stratégies et de scripts de Pine qui ont été collectés et transférés.

FMZ ne prend pas seulement en charge le langage Pine, mais également la fonctionnalité de dessin puissante du langage Pine. Les fonctionnalités de la plate-forme FMZ, les outils pratiques et la gestion efficace et facile, améliorent encore la fonctionnalité de la stratégie et du script de Pine. FMZ est basé sur la compatibilité avec le langage Pine, mais a également un certain degré d'extension, d'optimisation et de coupe.

Voici un bref aperçu de certaines des différences les plus évidentes:

  • 1 Politique de Pine sur FMZ, version identifiée au début du code//@versionet le code commence parstrategyindicatorLes phrases ne sont pas obligatoires et FMZ ne les prend pas en charge pour le moment.importImportélibraryfonction.

    Vous pouvez voir des stratégies comme celle-ci:

    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)

    Ou comme ceci:

    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)

    La FMZ peut être simplifiée comme suit:

    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)

    Ou encore:

    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 , Stratégie (script) Certains paramètres liés aux transactions sont définis par le paramètre "Pine language transaction class library" de l'interface de stratégie FMZ.

    • Modèles de clôture et de prix en temps réel
      Dans la vue commerciale, nous pouvons passer parstrategyLa fonctioncalc_on_every_tickParamètre pour définir la stratégie Le script exécute la logique de la stratégie en temps réel à chaque changement de prix, à ce moment-làcalc_on_every_tickLe paramètre doit être défini surtruePar défautcalc_on_every_tickLe paramètre estfalseLa logique de la stratégie n'est exécutée que lorsque la ligne KBAR de la stratégie est terminée.
      Sur FMZ, les paramètres sont définis à l'aide du modèle de la bibliothèque de classes "Pine Language Exchange".

      img

    • La précision des valeurs telles que le prix à l'exécution de la stratégie, la quantité de commande suivante, etc., doit être contrôlée sur la FMZ.
      Dans la vue de trading, il n'y a pas de problème de précision lors de la commande en temps réel car il n'y a que des tests d'analogie. Sur la FMZ, il est possible d'exécuter la stratégie Pine en temps réel.

    • Code du contrat à terme
      La variété de transaction sur FMZ, si elle est un contrat, a 2 attributs: "paire de transaction" et "code de contrat". En plus d'avoir besoin de définir clairement la paire de transaction en temps réel et en temps réel, il est également nécessaire de définir un code de contrat spécifique dans le paramètre "code de variété" du modèle de la bibliothèque de transactions en langage Pine. Par exemple, pour les contrats à perpétuité, remplissezswapLe code du contrat dépend de l'échange sur lequel vous opérez. Par exemple, vous pouvez remplir le code de tous les contrats trimestriels de certaines transactions.quarterLes codes de ces contrats correspondent à ceux définis dans la documentation de l'API Javascript/python/c++ de FMZ.

    Pour d'autres paramètres, tels que le nombre minimum de commandes, le nombre par défaut de commandes, etc., voir la documentation de la langue Pine surUne bibliothèque d'échanges de langues PineUne introduction aux paramètres

  • 3、runtime.debugruntime.logruntime.errorFonction d'extension de FMZ, utilisée pour le débogage。

    3 fonctions ont été ajoutées sur la plateforme FMZ pour le débogage.

    • runtime.debug: Cette fonction n'est généralement pas utilisée pour imprimer des informations sur les variables dans la console.

    • runtime.log: le contenu de la sortie du journal │ FMZ PINE a une fonction spécifique │

      pine
      runtime.log(1, 2, 3, close, high, ...),可以传多个参数。
    • runtime.error: provoque une erreur d'exécution avec le message d'erreur indiqué dans le paramètre message.

      pine
      runtime.error(message)
  • 4/ Une partie de la fonction de dessin est étendueoverlayparamètre

    Fonction de dessin de la langue Pine sur FMZplotplotshapeplotcharIl y en a plus.overlayPrise en charge des paramètres, permettant de spécifier des images dans le graphique principal ou le sous-graphique.overlayinstallationtrueLe tableau de bord a été modifié.falsePeindre dans les sous-diagrammes permet de dessiner simultanément le tableau principal et le sous-diagramme lorsque la stratégie Pine sur FMZ fonctionne.

  • 5、syminfo.mintickPrise de valeur de la variable intégrée

    syminfo.mintickLes variables intégrées sont définies comme les valeurs de mesure minimales de la variété actuelle.Offre ferme/BacktestingLa valeur est contrôlée par le paramètre de modèle Pricing Currency Precision dans la bibliothèque de classes de négociation du langage Pine dans l'interface. Le paramètre de Pricing Currency Precision est réglé sur 2, c'est-à-dire que le prix est précis au second degré de la somme des nombres minimes, lorsque le prix est le plus petit mouvement de 0,01syminfo.mintickLa valeur de l'équation est 0.01 <unk>.

  • 6/ Le prix moyen de FMZ PINE Script est celui qui inclut les frais de traitement

    Par exemple: le prix de commande est de 8000, la direction de vente, la quantité de 1 main ((un, une feuille), le prix moyen après la transaction n'est pas de 8000, moins de 8000 ((le coût comprend les frais de traitement)).

Base de la langue Pine

Lorsque nous commençons à apprendre les bases du langage Pine, il est possible que nous ne soyons pas familiers avec les instructions et la grammaire du code dans certains exemples. Peu importe que nous ne comprenions pas. Nous pouvons d'abord nous familiariser avec les concepts, comprendre le but du test, ou consulter la documentation du langage Pine de FMZ pour voir les instructions.

Exécution du modèle

Les stratégies de langage de Pine sont basées sur des graphiques et peuvent être comprises comme une série de calculs et d'opérations, exécutées dans un graphique par ordre chronologique, à partir des données les plus anciennes déjà chargées. La quantité de données initialement chargées sur le graphique est limitée.bar_indexRéférences à l'index de la barre de ligne K actuelle lors de l'exécution du script Pine.

pine
plot(bar_index, "bar_index")

img

plotLa fonction est l'une des fonctions que nous utiliserons le plus à l'avenir.bar_indexLa ligne est nomméebar_indexOn peut voir que la ligne nommée bar_index sur la première barre a une valeur de 0 et augmente de 1 avec l'augmentation de la barre vers la droite.

Les modèles d'exécution des stratégies varient selon les paramètres de la stratégie.收盘价模型et实时价模型Le concept de modèle de prix de clôture et de modèle de prix en temps réel a été présenté brièvement précédemment.

  • Modèle de prix de clôture

    Lorsque le code de stratégie est exécuté, le cycle de la barre K actuelle est terminé, et lorsque la barre K est fermée, le cycle de la barre K est terminé. À ce moment-là, la logique de la stratégie Pine est exécutée à nouveau, et le signal de transaction déclenché sera exécuté au début de la barre K suivante.

  • Modèle de prix en temps réel

    Lors de l'exécution du code de stratégie, la barre de ligne K actuelle, qu'elle soit fermée ou non, exécute une fois la logique de la stratégie Pine à chaque changement de situation, et le signal de transaction déclenché est immédiatement exécuté.

Lorsque la stratégie du langage Pine est exécutée de gauche à droite sur le graphique, la ligne K de la barre est divisée en历史Baret实时BarPour:

  • Le Bar de l'Histoire

    Lorsque la stratégie est définie comme un "modèle de prix réel" et commence à s'exécuter, toutes les barres K du graphique, à l'exception de la barre K située à droite,历史BarLa logique stratégique dans chaque racine历史BarIl suffit de le faire une fois.
    Lorsque la stratégie est définie comme un "modèle de prix de clôture" et qu'elle commence à s'exécuter, toutes les barres du graphique sont历史BarLa logique stratégique dans chaque racine历史BarIl suffit de le faire une fois.

    Calcul basé sur la barre historique:
    Le code de stratégie s'exécute une fois dans la barre d'historique en cours de fermeture, puis il continue à s'exécuter dans la barre d'historique suivante jusqu'à ce que toutes les barres d'historique aient été exécutées une fois.

  • Bar en temps réel

    Lorsque la stratégie est exécutée sur la dernière barre de ligne K à l'extrême droite, la barre devient une barre en temps réel. Lorsque la barre en temps réel est fermée, la barre devient une barre en temps réel passée (c'est-à-dire une barre d'historique). La barre en temps réel nouvelle est générée à l'extrême droite du graphique.

    Lorsque la stratégie est définie comme un "modèle de prix en temps réel" et commence à s'exécuter, une logique de stratégie est exécutée à chaque changement de situation dans la barre en temps réel.
    La stratégie définie comme "modèle de prix de clôture" n'affiche pas la barre en temps réel au début de l'exécution.

    Selon les calculs de Bar en temps réel:
    Si la stratégie est définie comme un graphique de "modèle de prix de clôture" et que la Bar n'est pas affichée en temps réel, le code de la stratégie n'est exécuté qu'une seule fois à la clôture de la Bar en cours.
    Si la stratégie est définie comme un "modèle de prix de placement réel", le calcul sur la barre en temps réel est complètement différent de celui sur la barre d'historique. Chaque changement de situation sur la barre en temps réel exécute un code de stratégie. Par exemple, les variables intégréeshighlowcloseDans la barre d'historique, ces valeurs sont déterminées, dans la barre en temps réel, ces valeurs peuvent changer à chaque fois que la situation change. Ainsi, les indicateurs tels que les données calculées sur la base de ces valeurs peuvent également changer en temps réel. Dans la barre en temps réelcloseLes prix sont toujours les plus récents.highetlowToujours représente le plus haut et le plus bas depuis le début de la barre en temps réel. Ces variables intégrées représentent la valeur finale lors de la dernière mise à jour de la barre en temps réel.

    Le mécanisme de retour en arrière lors de l'exécution de la stratégie sur la barre en temps réel (modèle de prix en temps réel):
    Lors de l'exécution de Bar en temps réel, chaque nouvelle génération de la stratégie exécute une variable définie par l'utilisateur précédemment réinitialisée, appelée un retour en arrière. Pour comprendre le mécanisme de retour en arrière, prenons l'exemple du code de test suivant.

    Avis:

    /*backtest ... .. . */

    Le paquet contient des informations de configuration de retour enregistrées sous forme de code sur la plate-forme 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

    Nous n'avons examiné que les scènes exécutées en temps réel dans le Bar, donc nous avons utilisénot barstate.ishistoryRestriction d'expression: n variables sont ajoutées uniquement en temps réel à Bar et utilisées avant et après l'exécution d'une opération d'agrégationruntime.logLes informations de sortie de la fonction sont dans le journal de stratégie.plotLa courbe tracée n peut être vue comme n ayant toujours été 0 lorsque la stratégie était en cours d'exécution dans la barre d'historique. Lorsque l'opération a été exécutée dans la barre en temps réel, elle a déclenché n actions cumulées de 1 et n actions cumulées de 1 ont été exécutées à chaque tour d'exécution de la stratégie sur la barre en temps réel. On peut observer à partir des informations du journal que chaque tour de réexécution du code de la stratégie n est réinitialisé à la valeur de la dernière commande de la stratégie d'exécution de la barre en temps réel.

    Pour résumer:
    1 Lorsque la stratégie commence à s'exécuter dans la barre en temps réel, un code de stratégie est exécuté à chaque mise à jour de la situation.
    2. Lors de l'exécution sur la barre en temps réel, les variables sont renvoyées avant chaque exécution du code de stratégie.
    3/ Lors de l'exécution sur la barre en temps réel, les variables sont soumises une fois lors de la mise à jour de la clôture.

    Les opérations de dessin comme les courbes sur le graphique peuvent également entraîner un redessin, car les données sont récurrentes, par exemple, nous avons modifié le code de test que nous venons de tester, test sur disque dur:

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

    Capture d'écran du moment A
    img

    Capture d'écran du moment B
    img

    Nous avons seulement modifié la phrase suivante:n := open > close ? n + 1 : nComme on peut le voir sur le premier graphique (moment A), le prix d'ouverture étant supérieur au prix de clôture (moment B), le prix d'ouverture est inférieur au prix de clôture (moment A), le prix n est renouvelé et n n est pas renouvelé. La courbe de la courbe n est immédiatement redessinée, alors que le n sur la courbe est de 4.

  • Contexte de la variable dans la fonction

    Examinons ensemble les variables dans les fonctions du langage de Pine. Selon les descriptions de certains didacticiels de Pine, les variables dans les fonctions diffèrent des variables extérieures aux fonctions de la façon suivante:

    L'historique des variables de la série utilisée dans une fonction Pine est créé par chaque appel consécutif de la fonction. Si la fonction n'est pas appelée dans chaque colonne de l'exécution du script, cela entraînera une différence entre les valeurs d'historique des séries internes et externes de la fonction. Par conséquent, si la fonction n'est pas appelée dans chaque colonne, les séries qui utilisent la même valeur d'indexation et qui sont référencées à l'intérieur et à l'extérieur de la fonction ne référenceront pas les mêmes points d'historique.

    Il n'y a pas de problème, nous l'avons compris avec un code de test exécuté sur 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)

    Capture d'écran de la réception en cours

    img

    Le code de test est relativement simple et consiste essentiellement à examiner les données citées de deux manières:f(a) => a[1]etf2() => close[1]

    • f(a) => a[1]: utilisation de paramètres de sortie, fonction retournée en derniera[1]

    • f2() => close[1]Utilisation directe de variables intégréesclose, retourne la fonction en dernierclose[1]

    []Symbole utilisé pour les opérations de référence des valeurs historiques des variables de la série de données, close[1] c'est-à-dire en citant le prix de clôture de la barre précédant le prix de clôture actuel. Notre code de test présente 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 A<unk>, de couleur rouge, quand oneBarInTwo est vraie, puis dessinez la position sur l'axe Y comme suit:f(close)Retourne une valeur

    • plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
      Dessinez un caractère sur B<unk>, de couleur verte, et dessinez-le lorsque oneBarInTwo est vraie, la position dessinée (sur l'axe Y) estf2()Retourne une valeur

    • plot(close[2], title = "close[2]", color = color.red, overlay = true)
      La ligne, colorée en rouge, est dessinée comme suit (sur l'axe Y):close[2]C'est-à-dire le prix de clôture sur la barre actuelle (à la 2ème ligne de la barre précédente, à la 2ème ligne de la gauche).

    • plot(close[1], title = "close[1]", color = color.green, overlay = true)
      La couleur de la ligne est le vert et la position (sur l'axe Y) est:close[1]C'est-à-dire le prix de clôture sur la barre de la première ligne (à gauche) de la barre actuelle.

    Les fonctionnalités utilisées pour marquer le dessin A sont visibles à travers la capture d'écran de fonctionnement de la rétroaction de la stratégief(a) => a[1]et les fonctions utilisées pour marquer Bf2() => close[1]Ils sont utilisés.[1] pour faire référence aux données historiques de la série de données, mais la position des marqueurs "A" et "B" sur le graphique est complètement différente. La position du marqueur "A" est toujours sur la ligne rouge, c'est-à-dire le code de la stratégieplot(close[2], title = "close[2]", color = color.red, overlay = true)La ligne est dessinée et les données utilisées sont:close[2]

    img

    La raison en est l'indexation par la barre de ligne K, qui est une variable intégrée.bar_indexCalculer si les marqueurs "A" et "B" doivent être dessinés. Les marqueurs "A" et "B" ne doivent pas être dessinés sur chaque barre de ligne K.f(a) => a[1]Si la fonction n'est pas appelée sur chaque barre, les valeurs citées de cette façon sont liées à la fonctionf2() => close[1]La valeur de référence de cette façon est différente (même si les deux utilisent[1] avec le même index).

  • Certaines fonctions intégrées doivent être calculées sur chaque barre pour pouvoir calculer correctement leur résultat.

    Pour illustrer cela, prenons un exemple simple:

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

    Nous allons appeler la fonction en code.ta.barssince(close < close[1])écrite dans un opérateur triangulairecondition ? value1 : value2Cela a entraîné la mort de plus de la moitié de la population.close > close[1]On appelle la fonction ta.barssince.ta.barssinceLa fonction est calculée à partir du dernierclose < close[1]Le nombre de lignes K au moment de la création. Lorsque la fonction ta.barssince est appelée, elle est 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, lorsque la fonction ta.barssince est appelée.[Il n'y a pas de siège, donc pas de siège le plus récent

    ta.barssince: Lorsqu'elle est appelée, la fonction renvoie na。 si cette condition n'a jamais été remplie avant la ligne K actuelle.

    Comme le montre la figure :

    img

    Donc, quand on dessine le diagramme, on ne dessine que les données où la variable res a une valeur ((-1) }}.

    Pour éviter ce problème, nous n'utilisons queta.barssince(close < close[1])L'appel de la fonction est tiré de l'opérateur triangulaire et écrit en dehors de n'importe quelle branche conditionnelle possible. Il permet d'effectuer des calculs sur chaque ligne K Bar.

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

    img

Séquence chronologique

Le concept de séquence temporelle est très important dans le langage Pine, c'est un concept que nous devons comprendre lorsque nous apprenons le langage Pine. La séquence temporelle n'est pas un type, mais une structure de base pour stocker une succession de valeurs de variables au fil du temps, nous savons que le script Pine est basé sur des graphiques, dont le contenu le plus basique est le diagramme de ligne K. La séquence temporelle dont chaque valeur est associée à une barre de temps de ligne K.openest une variable intégrée du langage Pine (built-in) dont la structure est la séquence de temps de stockage du prix d'ouverture de chaque ligne K de Bar. Elle peut être interprétée commeopenCette structure de séquence de temps représente le prix d'ouverture de toutes les barres de ligne K de la ligne K actuelle depuis la première barre du début jusqu'à la barre de l'exécution du script actuel. Si la ligne K actuelle est une période de 5 minutes, nous utilisons le code de la stratégie Pine pour faire référence à ((ou)openIl s'agit du prix d'ouverture de la ligne K Bar à l'exécution actuelle du code de la stratégie.[]Opérateur: Lorsque la stratégie Pine est exécutée sur une barre de ligne K, utilisezopen[1]Affichage de référenceopenLe prix d'ouverture de la première barre de ligne K exécutée par le script en cours dans la séquence de temps (c'est-à-dire le prix d'ouverture de la dernière période de ligne K).

  • Les variables de la séquence temporelle sont très faciles à calculer.
    Nous avons construit une fonction.ta.cumPar 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 :

    pine
    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 similitudes.ta.cumUne telle fonction intégrée peut traiter directement les données de la séquence temporelle, par exempleta.cumLe premier est d'accumuler les valeurs correspondantes des variables importées sur chaque barre de K, et ensuite nous utilisons un graphique pour faciliter la compréhension.

    Le processus d'exécution de la stratégie est basé sur la variable bar_index
    | - | - | - | - |
    La stratégie fonctionne sur la première ligne de K, Bar ≠ 0 ≠ 1 ≠ 1.
    La stratégie fonctionne sur la deuxième ligne de K, Bar, où 1 est le nombre 1 et où 2 est le nombre 2.
    La stratégie fonctionne sur la troisième racine de K, Bar ≠ 2 ≠ 1 ≠ 3.
    |...|...|...|...|
    La stratégie est exécutée sur la première ligne K de N+1

    On peut voir que v1, v2 et même bar_index sont en fait des structures de séquences temporelles et que chaque barre contient des données correspondantes. Ce code de test ne diffère pas entre le "modèle de prix en temps réel" et le "modèle de prix de clôture" que si le Bar est affiché sur le graphique. Pour mesurer la vitesse, nous utilisons le test de retour du "modèle de prix de clôture".

    img

    Parce que la variable v1 est 1 sur chaque barre.ta.cum(v1)Comme la fonction est exécutée sur la première ligne Bar de K, et qu'il n'y a que la première ligne Bar, le résultat est 1, et la valeur est donnée à la variable v2。
    Quandta.cum(v1)Lorsqu'il est exécuté sur la deuxième ligne K Bar, il y a déjà 2 lignes K Bar ((la première correspondant à la variable bar_index est 0, la deuxième correspondant à la variable bar_index est 1), donc le résultat est 2, attribué à la variable v2, et ainsi de suite. On peut en fait observer que v2 est le nombre de lignes K Bar dans le graphique, puisque l'index des lignes Kbar_indexC'est une augmentation de 0, alorsbar_index + 1En fait, c'est le nombre de lignes de K. On peut voir les lignes dans le diagramme d'observation.v2etbar_indexC'est vrai que c'est une répétition.

    img

    Je peux aussi utiliserta.cumLa fonction interne calcule la somme des prix de clôture de toutes les bars sur le graphique actuel, et peut être simplement écrite ainsi:ta.cum(close), lorsque la stratégie est exécutée sur la barre de temps réel sur la droiteta.cum(close)Le résultat obtenu est la somme des prix de clôture de toutes les barres sur le graphique (sans fonctionner à droite, il suffit d'ajouter à la barre actuelle).

    Les variables de la séquence temporelle peuvent également être calculées à l'aide d'opérateurs, par exemple:ta.sma(high - low, 14)et les variables intégrées.high(le prix le plus élevé de la barre K) moinslow(K-Line Bar au prix le plus bas)ta.smaLa fonction demande la moyenne.

  • Les résultats des appels de fonctions laissent également une trace de valeur dans la séquence 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 est observé en cours de fonctionnement lors de la rétro-analyse.v1etv2Les valeurs sont les mêmes, et les lignes dessinées sur le graphique se chevauchent parfaitement. Les résultats des calculs de l'appel de la fonction laissent des traces de valeurs dans la séquence de temps, par exemple le codeta.highest(high, 10)[1]Parmi eux,ta.highest(high, 10)Les résultats de l'appel de fonction peuvent également être utilisés[1] pour citer sa valeur historique.ta.highest(high, 10)Le résultat estta.highest(high[1], 10)Alors ?ta.highest(high[1], 10)etta.highest(high, 10)[1]C'est tout à fait équivalent.

    La validation de l'information de sortie est effectuée par une autre fonction de diagramme:

    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)

    On peut voir les valeurs des variables a et b dans la séquence temporelle affichées au-dessus et au-dessous de la barre correspondante. Le code du dessin peut être conservé pendant l'apprentissage, car il peut être nécessaire d'envoyer souvent des informations sur le graphique pour les observer lors de tests et d'expériences.

    img

Structure du scénario

Structure générale

Dans la première partie du tutoriel, nous avons résumé les différences entre l'utilisation du langage Pine sur FMZ et sur Trading View. Le code Pine sur FMZ peut être écrit sans numéro de version.indicator()strategy()Et, pour le moment, pas de soutienlibrary()Bien sûr, pour être compatible avec les versions antérieures du script Pine, la stratégie a été écrite comme suit://@version=5indicator()strategy()Il est possible de modifier les paramètres de certaines stratégies.strategy()Les paramètres de transfert dans une fonction.

<version> <declaration_statement> <code>

<version>Les informations de contrôle de version peuvent être supprimées.

Notes de rédaction

Langue utilisée par les Pine//En tant que commentaire à une ligne, le langage Pine n'ayant pas de commentaire à plusieurs lignes./**/Utilisé pour les notes en plusieurs lignes.

Le code

Les lignes qui ne sont pas des commentaires ou des instructions du compilateur dans un script sont des déclarations, elles implémentent l'algorithme du script. Une déclaration peut être l'un de ces éléments.

  • Déclaration de la variable
  • Réattribution de la variable
  • Déclaration de fonction
  • Appels de fonctions intégrés, appels de fonctions définis par l'utilisateur
  • ifforwhileouswitchStructure de l'équation

Les phrases peuvent être classées de plusieurs façons.

  • Certaines expressions peuvent être exprimées en une seule ligne, comme la plupart des déclarations de variables, qui ne contiennent qu'une seule ligne d'appel de fonction ou une seule ligne de déclaration de fonction. D'autres, comme les structures, ont toujours besoin de plusieurs lignes, car elles nécessitent un bloc local.
  • Les déclarations globales d'un script (c'est-à-dire les parties qui ne font pas partie d'un bloc local) ne peuvent pas être considérées comme空格ou制表符Les lignes qui commencent à la première position de la ligne font, par définition, partie de la portée globale du script.
  • Les déclarations de structures ou de fonctions à plusieurs lignes nécessitent toujours unlocal block。 Un bloc local doit se réduire à un sigle ou à quatre espaces (sinon, il sera décodé comme une suite de la ligne de code précédente, c'est-à-dire jugé comme une continuité de la ligne de code précédente), chaque bloc local définissant un autre domaine local。
  • Plusieurs phrases à une seule ligne peuvent être enchaînées dans une seule ligne en utilisant la virgule ((,) comme séparateur.
  • Une ligne peut contenir des commentaires ou seulement des commentaires.
  • Les lignes peuvent également être enroulées (continuer sur plusieurs lignes).

Par exemple, comprenant trois blocs locaux, un dans la déclaration de fonction personnalisée et deux dans la déclaration de variable utilisant la structure if, le code suivant:

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

Modifier le code

Les lignes longues peuvent être divisées en plusieurs lignes, ou " enroulées " vers le haut. Les lignes enroulées doivent être réduites dans n'importe quel nombre d'espaces, à condition qu'elles ne soient pas des multiples de 4 (ces limites sont utilisées pour réduire les blocs locaux).

pine
a = open + high + low + close

Le nombre d'espaces à réduire par ligne n'est pas un multiple de 4):

pine
a = open + high + low + close

Un appel à un long plot ((() peut être condensé en:

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)

Cependant, comme le bloc local doit grammaticalement commencer par une incrustation (((4 espaces ou 1 sigle), lorsque vous le divisez sur la ligne suivante, la partie continue de l'instruction doit commencer par plus d'une incrustation (((qui n'est pas égal au multiple de 4 espaces). Par exemple:

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

Identificateur et opérateur

Identifiant

Avant d'entendre parler de variables, il faut d'abord comprendre le concept d'identifiant de chaîne.fonctionetLes variablesLe nom d'une variable (ou d'une fonction)fonctionComme nous le verrons plus loin dans ce tutoriel, nous allons d'abord apprendre le symbole de l'oignon, <unk>。

  • 1 - Les identifiants doivent être en majuscules(A-Z)ou en minuscule(a-z)Alphabets ou soulignés(_)Début, le premier caractère de l'identifiant ▽
  • 2, le caractère suivant le premier caractère de l'identifiant peut êtreLes lettresSous-ligneouNuméros
  • 3 Les noms des identifiants sont en majuscules pour les distinguer.

Par exemple, les noms suivants:

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

Comme la plupart des langages de programmation, le langage Pine propose des suggestions d'écriture.

  • 1, les lettres entières en majuscules sont utilisées pour nommer les constantes.
    1. UtilisationRègles du Mont des CaméliasNom utilisé pour d'autres identifiants.
pine
// 命名变量、常量 GREEN_COLOR = #4CAF50 MAX_LOOKBACK = 100 int fastLength = 7 // 命名函数 zeroOne(boolValue) => boolValue ? 1 : 0

Outil de calcul

Les opérateurs sont des symboles d'opérateur utilisés dans les langages de programmation pour construire des expressions, et les expressions sont des règles de calcul conçues pour un certain type de calcul lorsque nous écrivons des stratégies. Les opérateurs du langage Pine sont classés selon leur fonctionnalité en:

Les opérateurs d'attribution, d'arithmétique, de comparaison, de logique,? : Les opérateurs triangulaires,[]Opérateur de référence historique:

avec un opérateur arithmétique*Par exemple, le code de test suivant est utilisé pour distinguer les types de problèmes résultant des résultats retournés par l'opérateur de langage Pine dans Trading View:

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)

La compilation d'erreurs lors de l'exécution de ce script dans Trading View est due au fait queadjustedLength = lenInput * factorOn obtientseries intCependant,ta.emaLe second paramètre de la fonction ne supporte pas ce type. Cependant, il n'y a pas de restrictions strictes de ce type sur FMZ, et le code ci-dessus fonctionne normalement.

Voici quelques exemples de l'utilisation des différents opérateurs:


Opérateur d'attribution

Il existe deux types d'opérateurs d'attribution:=:=C'est ce que nous avons vu dans quelques exemples au début du tutoriel.

=Opérateur utilisé pour l'initialisation ou la déclaration d'une variable.=Les variables après initialization, déclaration et attribution commencent par cette valeur sur chaque barre suivante. Ce sont des déclarations de variables valides:

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)

Avisa = closeUne déclaration d'attribution, où la variable a de chaque barre est le prix de clôture actuel de cette barre (closer). Les autres variablesbcdLa résistance à la corrosion est inchangée et peut être testée dans un système de rétroaction sur la FMZ. Le résultat peut être vu sur un diagramme.

:=Il est utilisé pour réattribuer des valeurs à des variables existantes.:=L'opérateur est utilisé pour modifier la valeur d'une variable déjà déclarée et initialisée.
Si vous utilisez:=L'opérateur attribue une valeur à une variable qui n'a pas été initialiée ou déclarée, ce qui entraîne des erreurs, par exemple:

pine
a := 0

Alors,:=Les opérateurs d'attribution sont généralement utilisés pour réattribuer une valeur à une variable existante, par exemple:

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

Si vous jugezclose > open(c'est-à-dire que le BAR actuel est le rayonnement solaire), la variable a est la valeur réelle ((true)) ≠, alors le code dans le bloc local de la déclaration if est exécuté.b := b + 1, avec l'opérateur d'attribution:=On redéfinit b en ajoutant un 1 ◦ puis on utilise la fonction plot pour tracer les valeurs de la variable b sur chaque BAR de la séquence temporelle, en les reliant en ligne ◦

Est-ce que nous pensons qu'en créant un rayon de soleil BAR, b continuera à accumuler 1 ? Bien sûr que non, nous n'avons pas utilisé de mot-clé pour la déclaration de la variable b, initialité 0.b=0On peut donc voir que le résultat de ce code est de réinitialiser la variable b à 0 à chaque fois si la variable a est vraie.close > openDonc, pour ce tour de programmation, b est une addition de 1, pour le tracé de la fonction de tracé, b est 1, mais pour le prochain tour de programmation, b est réattribué à 0. C'est là aussi que les débutants du langage Pine peuvent facilement se tromper.

En ce qui concerne les opérateurs d'attribution, il faut développer deux mots-clés:varvarip

  • var

    En fait, ce mot clé, nous l'avons déjà vu et utilisé dans les tutoriels précédents, mais nous ne l'avons pas exploré en détail à ce moment-là.

    var est un mot-clé utilisé pour l'allocation et l'initialization de variables à la fois. Généralement, la syntaxe d'attribution de variables qui ne contient pas le mot-clé var entraîne la suppression de la valeur de la variable chaque fois que les données sont mises à jour. En revanche, lorsqu'on utilise le mot-clé var pour l'allocation de variables, elles conservent leur état même si les données sont mises à jour.

    Nous utilisons toujours cet exemple, mais nous utilisons quand nous donnons une valeur à b.varLes mots clés:

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

    varLe mot-clé permet à la variable b de n'exécuter que la première attribution initiale, et de ne plus réinitialiser b à 0 à chaque fois que la logique de stratégie est exécutée, de sorte que la ligne dessinée à partir de l'exécution peut être observée pour obtenir b, soit le nombre de lignes de y qui ont été affichées lors de la mesure du BAR de la ligne K actuelle.

    Les variables d'une déclaration var peuvent être écrites non seulement au niveau global, mais aussi dans des blocs de code, comme dans cet exemple:

    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' conserve le prix de clôture du premier pilier de la série.
    La variable 'b' maintient le prix de clôture de la première barre de prix de l'aluminium vert de la série.
    La variable 'c' maintient le prix de clôture de la dixième pomme de terre verte de la série.

  • varip

    varipNous avons vu ce mot-clé pour la première fois, et nous pouvons voir sa description:

    varip ((var intrabar persist) est un mot-clé pour les variables d'allocation et d'initialisation ponctuelle. Il est similaire au mot-clé var, mais les variables utilisant la déclaration varip conservent leur valeur entre les mises à jour en ligne K en temps réel.

    C'est facile à comprendre avec des exemples.

    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

    Le code de test fonctionne différemment sur les modèles de prix de clôture et de prix en temps réel:

    Les prix en temps réel:
    Rappelez-vous que nous avons expliqué précédemment que la stratégie est exécutée en temps réel, en temps réel, en temps réel, en temps réel.varvaripVariables déclaréesiiiChaque fois que le code de la stratégie est exécuté, des opérations d'augmentation sont effectuées. On peut donc voir que les chiffres affichés sur la ligne KBAR du résultat de la rétro-mesure augmentent un par un. Lorsque la phase de la ligne K historique se termine, la phase de la ligne K en temps réel commence.i := i + 1etii := ii + 1La différence est que ii est modifié à chaque fois. Bien que i soit modifié à chaque fois, la logique d'exécution de la stratégie du prochain tour reprend la valeur précédente (vous vous souvenez du mécanisme de retour en arrière que nous avons expliqué dans la section précédente "Exécution du modèle" ?), jusqu'à ce que la ligne KBAR actuelle soit terminée pour mettre à jour la valeur de détermination de i (c'est-à-dire que la logique d'exécution de la stratégie du prochain tour ne reprend plus la valeur précédente).

    Le modèle de clôture:
    Puisque le modèle de prix de clôture n'exécute une logique stratégique qu'à chaque K-ligne BAR. Dans le modèle de prix de clôture, les phases historiques de la ligne K et les phases de la ligne K en temps réel, les variables de la déclaration var, varip se comportent de manière progressive dans l'exemple ci-dessus, avec une augmentation de 1 pour chaque K-ligne BAR.


Opérateur arithmétique
Outil de calculillustrer
+Le plus grand
-Réduction
*La multiplication
/Décision de justice
%Des modèles

+-Les opérateurs peuvent être utilisés en tant qu'opérateurs binaires ou en tant qu'opérateurs unitaires. Les autres opérateurs d'arithmétique ne peuvent être utilisés qu'en tant qu'opérateurs binaires.

1 , les opérateurs d'arithmétique sont des types de valeur numérique des deux côtés, ce qui donne un type de valeur numérique, un type entier ou un nombre de points flottants selon le résultat de l'opération.
2. Si le nombre d'opérations est une chaîne, l'opérateur est+, est calculé comme une chaîne de caractères, la valeur est convertie en chaîne de caractères, puis les chaînes sont assemblées. Si c'est un autre opérateur d'arithmétique, on essaie de convertir la chaîne de caractères en valeur et de l'opérer.
3 Si le nombre d'opérations est na, le résultat est nul, et NaN apparaît lors de l'impression sur 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

Le langage Pine sur FMZ est un peu différent de celui de Trading View, le langage Pine sur FMZ n'est pas très exigeant pour les types de variables. Par exemple:

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

Si le système ne parvient pas à calculer une chaîne de caractères non numérique, le résultat du système est une valeur nulle.


Comparer les opérateurs

Les opérateurs de comparaison sont tous des opérateurs binaires.

Outil de calculillustrer
<inférieure à
>Plus que
<=inférieur à égal à
>=Plus est égal à
==équivalent
!=Les inégalités

Exemple de test :

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

Comme vous pouvez le voir, l'opérateur de comparaison est très simple à utiliser, mais c'est aussi l'opérateur que nous utilisons le plus souvent pour écrire des stratégies. Vous pouvez comparer des valeurs et des variables intégrées, par exemplecloseopenattendez.
Comme pour les opérateurs de calcul, la FMZ est différente de la Pin de Trading View, la FMZ n'a pas de type d'exigence particulièrement rigide, de sorte que de telles déclarationsd = "1" >= 2 Il n'y a pas de message d'erreur sur FMZ, la chaîne de caractères est d'abord convertie en valeur numérique avant d'être comparée. Il y a un message d'erreur sur Trading View.


Opérateur logique
Outil de calculNom du codeillustrer
Pas tout à fait.notUnité d'opérateur, non opérationnelle
etandOpérateur binaire, avec (et)
ouorOpérateur binaire, ou opération

Parler d'opérateur logique, c'est parler de table des valeurs réelles. Comme nous l'avons appris au lycée, mais ici nous testons et apprenons dans le système de rétroaction:

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

Pour éviter que le système de suivi ne soit affecté par l'impression continue d'informations, nous utilisonsruntime.error("stop")L'expression est utilisée pour exécuter une impression, puis lancer une erreur anormale qui arrête le test de retour. On peut alors observer l'information en sortie et constater que le contenu de l'impression et la table de valeurs réelles sont en fait les mêmes.


Opérateur de trinité

Utilisation de l'opérateur trinitaire? : Expression triangulaire combinée à un nombre d'opérationscondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseNous l'avons déjà vu dans les cours précédents. Les expressions dites triangulaires, ou opérateurs triangulaires, signifient qu'il y a trois opérations en tout.

condition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseLes résultats sont les suivants:conditionest la condition de jugement si la valeur de l'expression de la règle de vérité est:valueWhenConditionIsTrueSiconditionLa valeur de l'expression estvalueWhenConditionIsFalse

Il n'y a pas beaucoup d'utilité pratique, mais des exemples qui peuvent être utiles pour la démonstration:

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)

Si vous rencontrez une croix, ça ne fait rien ! L'expression triangulaire peut aussi être encastrée, comme nous l'avons fait dans le tutoriel précédent.

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)

C'est l'équivalent decondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseDansvalueWhenConditionIsTruevalueWhenConditionIsFalse, et utilise une autre expression trinitaire au lieu de ▽.


Opérateur historique

Utilisation de l'opérateur historique[]Les valeurs historiques sont les valeurs de la variable sur la ligne K BAR précédant la ligne K BAR actuelle au moment de l'exécution du script.[]Les opérateurs sont utilisés après les appels de variables, d'expressions et de fonctions.[]Le nombre dans les crochets est le décalage de l'historique à laquelle nous faisons référence par rapport à la ligne K BAR actuelle. Par exemple, si je veux faire référence à la clôture d'une ligne K BAR, j'écrirai:close[1]

Nous avons déjà vu une écriture similaire dans les cours précédents:

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

[]L'opérateur ne peut être utilisé qu'une seule fois sur la même valeur, donc cette écriture est erronée:

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

Vous pouvez voir ici, certains de mes camarades disent que l'opérateur[]C'est pour les structures de séries, qui ressemblent beaucoup à des structures de séries et à des ensembles !
Voici un exemple pour illustrer la différence entre une série et un tableau dans le langage 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")

Bien quea = close[1][2]Je ne sais pas si j'ai bien compris, mais:

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

Il n'y a pas d'erreur à le décomposer, si l'on le prend comme un tableau ordinaire.b = close[1]Après avoir attribué une valeur, b devrait être un nombre, maisc = b[1], b peut toujours être réutilisé par l'opérateur historique pour faire référence à la valeur historique. Comme on peut le voir dans le langage de Pine, le concept de série n'est pas aussi simple qu'un tableau. On peut l'interpréter comme la valeur historique sur la barre précédente de close, b est aussi une structure de séquence temporelle, et on peut continuer à faire référence à sa valeur historique.

Nous pouvons faire glisser le graphique vers l'extrême gauche et observer que les valeurs de b et c sont nulles sur la première ligne K ((na) <unk>). C'est parce que lorsque le script est exécuté sur la première ligne K BAR, aucune valeur historique n'est citée pour les cycles un ou deux en avant, elle n'existe pas.nanzEn fait, nous avons déjà abordé cela dans notre étude précédente.nznaLes fonctions, vous vous souvenez de quel chapitre?) traitent spécifiquement des valeurs vides, par exemple:

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

C'est un traitement qui peut se référer à une valeur nulle (null).


Priorité des opérateurs

Nous avons déjà appris beaucoup d'opérateurs du langage Pine, qui forment des expressions en utilisant diverses combinaisons d'opérateurs et de nombres. Alors, quelle est la priorité de ces opérations lors du calcul dans les expressions?

Les prioritésOutil de calcul
9[]
8Les opérateurs unitaires sont ``` + - et non ``
7*/%
6Les opérateurs binaires sont +, -
5><>=<=
4==!=
3and
2or
1?:

Les parties de l'expression qui ont la priorité la plus élevée sont traitées en premier, et si elles ont la même priorité, elles sont traitées de gauche à droite. Si vous voulez forcer une partie à être traité en premier, vous pouvez utiliser()Emballez une expression qui impose d'opérer cette partie d'abord.

Les variables

Déclaration de la variable

Nous avons déjà étudié la notion d'identifiant de variable, qui est le nom donné à une variable en tant que nom de la variable. On peut donc dire que la variable est l'identifiant de la valeur conservée. Alors, comment déclarer une variable? Quelles sont les règles pour déclarer une variable?

  • Modèle de déclaration:
    La première chose à écrire quand on déclare une variable, c'est le "modèle de déclaration". Il y a trois modèles de déclaration de variables:
    1 - Utilisez des mots clésvar
    2/ Utilisez des mots clésvarip
    3/ Ne rien écrire.

    varvaripLe mot-clé a été étudié dans la section précédente sur les opérateurs d'attribution et n'est plus abordé ici. Si le mode de déclaration de la variable n'est pas écrit, par exemple:i = 1En fait, comme nous l'avons déjà dit, les variables déclarées et attribuées sont exécutées sur chaque ligne KBAR.

  • taper
    Le langage Pine sur FMZ n'est pas très strict sur les exigences de type et peut être omis. Cependant, pour être compatible avec les stratégies de script sur Trading View, les variables peuvent également être déclarées avec un type. Par exemple:

    int i = 0 float f = 1.1

    Les types sont plus exigeants dans la vue de trading, et l'utilisation du code suivant dans la vue de trading entraînera des erreurs:

    baseLine0 = na // compile time error!
  • Identifiant
    L'identifiant est le nom d'une variable dont nous avons parlé dans le chapitre précédent, voir: https://www.fmz.com/bbs-topic/9390#标识符

En résumé, la déclaration d'une variable peut s'écrire:

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

L'opérateur d'attribution est utilisé ici:=Les valeurs peuvent être des chaînes de caractères, des valeurs, des expressions, des appels de fonctions, ou encore des variables.ifforwhileouswitchLes structures sont des mots-clés et des expressions structurées dont nous parlerons plus en détail dans les cours suivants. En fait, nous avons déjà appris l'attribution d'une simple expression if dans les cours précédents, nous pouvons revenir en arrière.

Nous allons nous concentrer sur la fonction d'entrée, une fonction que nous utilisons fréquemment dans la conception et l'écriture de stratégies. C'est aussi une fonction très importante dans la conception de stratégies.

Fonction d'entrée:

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

La fonction d'entrée sur FMZ est un peu différente de celle de Trading View, mais elle est utilisée comme entrée de valeur attribuée pour les paramètres de stratégie. Voici un exemple détaillé de l'utilisation de la fonction d'entrée sur FMZ:

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)

La fonction d'entrée est souvent utilisée pour attribuer une valeur à une variable lors de la déclaration d'une variable. La fonction d'entrée sur FMZ dessine automatiquement les contrôles utilisés pour définir les paramètres de la stratégie sur l'interface de la stratégie FMZ. Les contrôles pris en charge sur FMZ incluent actuellement les cases de saisie de valeurs, les cases de saisie de texte, les cases déroulantes et la sélection de valeurs.

img

Nous vous présentons quelques paramètres principaux d'une fonction d'entrée:

  • defval: valeur par défaut de l'option de paramètre de stratégie définie par la fonction d'entrée, prend en charge les variables, les valeurs et les chaînes intégrées du langage Pine
  • title: Nom des paramètres affichés par la stratégie sur l'interface de la stratégie sur disque/rétrospective.
  • tooltip: Astuce de paramètre de stratégie, qui affiche le texte de ce paramètre lorsque la souris est suspendue sur le paramètre de stratégie.
  • group: nom de groupe de paramètres de la stratégie, qui peut être donné à un groupe de paramètres。

En plus de la déclaration et de l'attribution de variables individuelles, le langage Pine déclare un ensemble de variables et d'attributions:

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

Le plus courant est celui que nous utilisons.ta.macdComme l'indicateur MACD est un indicateur multilinéaire, la fonction calcule trois ensembles de données. On peut donc écrire:

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)

Il est facile de dessiner un diagramme MACD avec le code ci-dessus. Non seulement les fonctions intégrées peuvent renvoyer plusieurs variables, mais les fonctions personnalisées peuvent également renvoyer plusieurs données.

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)

L'utilisation de structures telles que if comme attribution de valeurs à plusieurs variables est similaire à celle de la fonction personnalisée ci-dessus.

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

Structure conditionnelle

Certaines fonctions ne peuvent pas être écrites dans un bloc de code local de branche conditionnelle, principalement les fonctions suivantes:

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

Le Trading View compile des rapports d'erreurs. Les restrictions sur FMZ ne sont pas aussi strictes, mais il est recommandé de suivre les spécifications de Trading View. Par exemple, bien que cela ne soit pas rapporté sur FMZ, il n'est pas recommandé de le faire.

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

Déclaration if

Voici un exemple:

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)

Points marquants: l'expression utilisée pour le jugement renvoie une valeur de Boole. Attention à la contraction. Il ne peut y avoir qu'une seule branche de la branche.

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

Puisque le bloc local de if n'est pas exécuté lorsque la ligne KBAR est négative, c'est-à-dire lorsque close < open, l'expression suivante de la phrase if est false. Il n'y a pas non plus de branche else à ce moment-là. La phrase if renvoie na.

Sentences de commutation

Les déclarations de commutation sont également des déclarations branchées qui sont utilisées pour concevoir différents chemins d'exécution selon certaines conditions. Les déclarations de commutation ont généralement les points clés suivants:

1, comme pour les expressions if et switch, il est possible de renvoyer une valeur.
2. Contrairement aux expressions de commutation dans d'autres langages, la commutation n'exécute qu'un seul bloc local de son code, de sorte qu'il n'est pas nécessaire d'écrire une déclaration de rupture (c'est-à-dire qu'il n'est pas nécessaire d'écrire des mots-clés tels que break).
3, chaque branche de switch peut écrire un bloc de code local, dont la dernière ligne est la valeur de retour ((il peut s'agir d'un sous-groupe de valeurs). Si aucune des branches n'a été exécutée, le bloc de code local est renvoyé.
4/ Déterminer l'emplacement d'une expression dans une structure de commutation, écrire une chaîne de caractères, une variable, une expression ou un appel de fonction.
5. switch permet de spécifier une valeur de retour qui est la valeur par défaut utilisée lorsqu'il n'y a pas d'autres conditions dans la structure.

On peut distinguer deux types de commutateurs, et nous allons voir un exemple à la fois pour comprendre comment ils sont utilisés.

1 avec une expressionswitchL'exemple suivant:

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)

Nous avons déjà étudié les fonctions d'entrée, et nous allons maintenant étudier deux fonctions similaires à l'entrée:input.stringinput.intfonction.
input.stringLe mot "script" est utilisé dans le texte de la requête.input.intLa fonction est utilisée pour renvoyer des valeurs entières.optionsL'utilisation des paramètresoptionsLes paramètres peuvent être transférés dans un ensemble composé de valeurs sélectives. Par exemple, dans l'exempleoptions=["EMA", "SMA", "RMA", "WMA"]etoptions=[5, 10, 20](Notez que l'un est un type de chaîne et l'autre un type de valeur numérique). Ainsi, les contrôles de l'interface de stratégie n'ont pas besoin de saisir des valeurs spécifiques, mais deviennent des cases déroulantes pour sélectionner les options fournies dans le paramètre options.

La valeur de la variable func est une chaîne de caractères, avec la variable func comme expression de la commutation (en tant que variable, appel de fonction, expression), pour déterminer quelle branche de la commutation est exécutée. Si la variable func ne peut pas correspondre à l'expression sur n'importe quelle branche de la commutation (c'est-à-dire égale), l'exécution du bloc de code de la branche par défaut s'exécute.runtime.error("error")La fonction a provoqué l'arrêt de l'exception de la stratégie.

Dans notre code de test ci-dessus, nous n'avons pas ajouté de runtime.error après la dernière ligne du bloc de code de la branche par défaut de switch[Un code tel que na, na] est nécessaire pour la compatibilité des valeurs de retour, mais il est possible d'ignorer ce code de compatibilité car il n'y a pas de type strictement requis sur FMZ. Il n'est donc pas nécessaire de prendre en compte la compatibilité des types des valeurs de retour des branches if, switch sur FMZ.

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)

Il n'y a pas d'erreur sur la FMZ, mais il y a une erreur sur la vue de trading.

2/ Non expriméswitch

Nous verrons plus loin.switchUne autre façon d'écrire le mot "sans" est de l'écrire sans expression.

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)

Comme on peut le voir dans l'exemple de code de test, switch va faire correspondre le bloc de code local qui exécute la branche comme étant le vrai bloc de code local. En général, les conditions de la branche après la déclaration de switch doivent être mutuellement récusatives.up = close > open // up = close < open En remplaçant le contenu de la note par le résultat de l'observation, on constate que la branche switch ne peut exécuter que la première branche. En outre, il faut veiller à ne pas écrire l'appel de la fonction dans la branche switch, car l'appel de la fonction sur chaque BAR peut causer des problèmes de calcul de données.switchDans l'exemple, la branche d'exécution est définie et ne peut pas être modifiée pendant le fonctionnement de la stratégie.)

Structure cyclique

Indications pour

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

L'instruction for est très simple à utiliser, car la boucle for peut retourner une valeur finale ((), ou retourner plusieurs valeurs, pour[a, b, c]). Comme dans le pseudo-code ci-dessus, les variables attribuées à la position de "valeur de retour" sont suivies d'une variable "compte" utilisée pour contrôler le nombre de cycles, la référence à d'autres valeurs, etc. La variable "compte" est attribuée comme "compte initial" avant le début du cycle, puis progressivement selon le paramètre "pace", et le cycle s'arrête lorsque la variable "compte" est supérieure au "compte final".

Utilisé dans la boucle forbreakMots-clés: Quand cela est faitbreakLe cycle s'arrête après la phrase.
Utilisé dans la boucle forcontinueMots-clés: Quand cela est faitcontinueLa phrase suivante est ignorée.continueLe code suivant exécute directement le prochain cycle. L'instruction for renvoie la valeur de la dernière exécution du cycle. Si aucun code n'a été exécuté, elle renvoie une valeur nulle.

Voici un exemple simple pour le démontrer:

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

Pour ... dans la phrase

for ... inIl y a deux formes de phrases, et le pseudo-code ci-dessous en est une illustration.

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

On peut voir que la principale différence entre les deux formes réside dans le contenu qui suit le mot-clé for, soit en utilisant une variable comme référence d'un élément de l'arrayon. L'une est en utilisant une structure de référence qui contient un sous-ensemble de variables d'index, d'éléments de l'arrayon.

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

Utilisez l'indexation lorsque cela est nécessaire.for [i, ele] in testArrayL'orthographe de l'anglais

Applications pour le cycle

Il est possible d'utiliser des fonctions intégrées fournies par le langage Pine pour effectuer des calculs de logique circulaire, d'écrire directement avec une structure circulaire ou de traiter avec des fonctions intégrées. Nous donnons deux exemples.

1, calculer la moyenne

Utilisez la conception de la structure circulaire:

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)

Dans l'exemple, on utilise la somme for cyclique, puis on calcule la moyenne.

Calculez la moyenne en utilisant directement la fonction intégrée:

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

Utilisation directe de fonctions intégréesta.smaIl est évidemment plus simple d'utiliser une fonction intégrée pour calculer l'indicateur de la ligne moyenne. On peut voir une parfaite concordance des résultats calculés dans la comparaison du graphique.

2 - La somme

Vous pouvez aussi utiliser l'exemple ci-dessus.

Utilisez la conception de la structure circulaire:

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)

Pour calculer la somme de tous les éléments d'une matrice, on peut utiliser un cycle ou une fonction intégrée.array.sumPour calculer.
Pour calculer l'addition directement à l'aide des fonctions intégrées:

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)

On peut voir que les données calculées sont parfaitement cohérentes sur le graphique.

Alors, si on peut faire tout cela avec des fonctions intégrées, pourquoi concevoir des cycles ?
1 Pour certaines opérations sur un tableau, calculer:
2. Revenir en arrière dans l'histoire, par exemple, pour savoir combien de points élevés dans le passé sont supérieurs aux points élevés du BAR actuel. Comme le point élevé du BAR actuel n'est connu que sur le BAR du script en cours d'exécution, un cycle est nécessaire pour revenir en arrière et analyser les points élevés du BAR passé.
3 Les fonctions intégrées du langage Pine ne peuvent pas compléter le calcul du BAR passé.

Déclaration while

whileL'instruction permet au code de la partie de la boucle d'être exécuté jusqu'à ce que la condition de jugement de la structure while soit false (false).

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

Les autres règles de while sont similaires à celles de la boucle for. La dernière ligne du bloc de code local du corps de la boucle est une valeur de retour, qui peut renvoyer plusieurs valeurs. L'exécution de la boucle s'effectue lorsque la condition de la boucle est vraie et s'arrête lorsque la condition est fausse.

Je vais vous montrer l'exemple d'un calcul de l'équation:

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)

On peut voir que l'utilisation de while en boucle est également très simple, mais on peut aussi concevoir des logiques de calcul qui ne peuvent pas être remplacées par des fonctions intégrées, par exemple pour calculer la multiplication par degrés:

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

Groupe

L'array de Pine est une matrice qui est une matrice en trois dimensions. Elle est généralement utilisée pour stocker une série de données en continu. L'array dans lequel les données individuelles sont stockées s'appelle l'array d'éléments. Les types d'éléments peuvent être: entiers, floats, chaînes, valeurs de couleur, valeurs de boule.[]Il faut utiliserarray.get()etarray.set()La fonction 。 est une fonction d'indexation de l'ordre des éléments dans l'arrêté si l'indexation du premier élément de l'arrêté est égale à 0 et celle du suivant est augmentée de 1。

Nous utilisons un code simple pour expliquer:

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

Déclaration de l'array

utiliserarray<int> afloat[] bLes ensembles de valeurs peuvent être attribués à des ensembles de valeurs qui déclarent des ensembles de valeurs ou qui déclarent une seule variable, par exemple:

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

Généralement utilisé pour l'initialization de variables d'une matricearray.newetarray.fromIl existe d'autres fonctions dans le langage Pine qui sont similaires à celles de array.new:array.new_int()array.new_bool()array.new_color()array.new_string()attendez.

Le mot-clé var peut aussi s'appliquer au mode de déclaration d'un tableau. Un tableau déclaré avec le mot-clé var n'est initialisé que sur la première ligne BAR.

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

On peut voir que les modifications de l'arrayon a sont déterminées de façon continue, sans être réinitialisées. L'arrayon b est initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement initialement inbarstate.islastPour l'impression en temps réel, il n'y a qu'un seul élément, la valeur 0。

Lire et écrire des éléments dans un tableau

Utilisez array.get pour obtenir les éléments dont l'index est spécifié dans l'array et utilisez array.set pour modifier les éléments dont l'index est spécifié dans l'array.

Le premier paramètre de array.get est l'array à traiter, le second l'index spécifié.
Le premier paramètre de array.set est l'array à traiter, le second l'index désigné, et le troisième l'élément à écrire.

L'exemple suivant est simple:

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

L'exemple initie le vert comme couleur de base, déclare et initie un tableau pour préserver la couleur, puis confère une transparence différente à la valeur de la couleur (en utilisant la fonction color.new). Le niveau de couleur est calculé en calculant la distance de la valeur maximale de BAR actuelle de high sur 100 cycles de revue. Plus la distance est proche de la valeur maximale de high sur les 100 derniers cycles de revue, plus le niveau est élevé, et plus la valeur de couleur correspondante est profonde.

Parcourir les éléments de l'arrêté

Comment parcourir un tableau, nous pouvons le faire avec les expressions for/for in/while que nous avons apprises précédemment.

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

Les trois méthodes de traversée donnent le même résultat.

Les ensembles peuvent être déclarés au niveau global du script, ou au niveau local de la fonction ou de la branche if.

Citation de données historiques

Pour l'utilisation d'éléments dans un tableau, la méthode suivante est équivalente, nous pouvons voir par l'exemple suivant que deux groupes de lignes sont dessinés sur le graphique, deux lignes dans chaque groupe, et que les deux lignes de chaque groupe sont exactement les mêmes.

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)

Fonctions d'ajout et de suppression d'un tableau

1, les fonctions associées aux opérations d'addition d'un tableau:

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

2 Les fonctions associées à la suppression d'un tableau:

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

Nous utilisons l'exemple suivant pour tester les opérations d'ajout et de retrait de ces ensembles.

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

Ajout et suppression d'applications: Arrays en tant que queue

On peut construire une structure de données appelée "cohorte" en utilisant des matrices et des fonctions d'addition et de suppression de matrices. Les matrices peuvent être utilisées pour calculer les moyennes mobiles des prix de tick. Certains de vos camarades se demanderont peut-être: pourquoi construire une structure de cohorte ?

Une queue est une structure couramment utilisée dans le domaine de la programmation, caractérisée par:

Les éléments qui entrent en premier dans la queue sortent en premier.

Cela permet de s'assurer que les données présentes dans la queue sont les dernières et que la longueur de la queue ne s'agrandit pas à l'infini (le code qui s'agrandit à l'infini ne peut être écrit qu'à midi, car il y a des problèmes entre le matin et le soir).

Dans l'exemple suivant, nous utilisons une structure de queue pour enregistrer le prix à chaque tick, calculer une moyenne mobile au niveau du tick, puis la comparer avec une moyenne mobile au niveau de la ligne K à 1 minute.

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

Notez que nous avons spécifié le mode de déclaration de l'arrayon a en utilisant le mot clévaripAinsi, chaque variation de prix est enregistrée dans un tableau a.

Fonctions de calcul et d'opérations d'arrêts courantes

Calculer les fonctions suivantes:

array.avg()Trouvez la moyenne de tous les éléments de l'array.array.min()Trouvez le plus petit élément de l'array.array.max()Trouvez le plus grand élément de l'array.array.stdev()Trouvez la différence standard de tous les éléments de l'array.array.sum()Trouver la somme de tous les éléments de l'array.

Fonctions liées à l'opération:
array.concat()Fusion ou connexion de deux ensembles.
array.copy()Copier une matrice
array.joinConnectez tous les éléments de l'array en une seule chaîne de caractères.
array.sort()Par ordre décroissant ou décroissant.
array.reverse()Arrayes inversées
array.slice()Découper un tableau.
array.includes()Éléments de jugement
array.indexof()Retourne l'index de la première occurrence de la valeur de l'entrée de paramètre. Si cette valeur n'est pas trouvée, retourne -1.
array.lastindexof()Trouver la dernière valeur qui apparaît.

Exemples de tests de fonctionnalités liées au calcul des ensembles:

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

Ce sont les fonctions de calcul de l'arrayon les plus couramment utilisées.

Exemple de fonctionnalités d'exploitation:

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

fonction

Fonctions personnalisées

Le langage Pine permet de concevoir des fonctions personnalisées, généralement avec les règles suivantes:

  1. Toutes les fonctions sont définies dans le champ global du script. Une fonction ne peut pas être déclarée dans une autre fonction.
    2/ Ne pas autoriser une fonction à s'appeler elle-même ((récursives)) dans son propre code.
    3/ En principe, toutes les langues PINE ont une fonction de dessin intégrée ().barcolor()、 fill()、 hline()、plot()、 plotbar()、 plotcandle()) ne peut pas être appelé dans une fonction personnalisée.
    Les fonctions peuvent être écrites en une seule ligne ou en plusieurs lignes. La dernière phrase renvoie la valeur de la fonction actuelle, qui peut être renvoyée sous forme d'éléments.

Nous avons utilisé plusieurs fois des fonctions personnalisées dans des tutoriels précédents, par exemple des fonctions personnalisées conçues en une seule ligne:

pine
barIsUp() => close > open

Cette fonction renvoie si le BAR actuel est un rayonnement solaire.

Fonctions personnalisées en plusieurs lignes:

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)

La fonction que nous avons nous-mêmes réalisée avec une fonction personnalisée de calcul de la moyenne de sma.

On peut également retourner des exemples de fonctions personnalisées pour deux 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)

Une fonction peut calculer une ligne rapide, une ligne lente, deux indicateurs de la ligne moyenne EMA.

Fonctions intégrées

Les fonctions intégrées peuvent facilement êtreNom de fichier:Les résultats de la recherche.

Les fonctions intégrées du langage Pine sont classées:

1 , fonction de traitement de chaînestr.Série
2/ Fonction de traitement des valeurs de couleurcolor.Série
3 - Fonction de saisie de paramètresinput.Série
4/ La fonction de calcul des indicesta.Série
5 - Fonction de dessinplot.Série
Fonctions de traitement d'arrayarray.Série
Fonctions liées aux transactionsstrategy.Série
Fonctions mathématiquesmath.Série
9), d'autres fonctions (traitement du temps, dessin de séries non-plot),request.Fonctions de séries, fonctions de traitement de types, etc.)

Fonction de transaction

strategy.Les fonctions de séries sont des fonctions que nous utilisons souvent dans la conception de stratégies et qui sont liées à la stratégie pour exécuter des opérations de transaction lors de leur exécution.


1、strategy.entry

strategy.entryUne fonction est une fonction de commande qui est importante pour nous quand nous écrivons des stratégies. Les paramètres qui sont importants pour cette fonction sont:id, direction, qty, whenattendez.

paramètre:

  • id: peut être interprété comme un nom donné à une position de négociation pour être utilisé comme référence. Il peut être utilisé comme référence pour l'annulation, la modification de l'ordre, la clôture de position.
  • direction: le paramètre est transmis si la direction de commande est faire plus (acheter)strategy.longCette variable interne est transmise si vous voulez faire une vente à découvert.strategy.shortCette variable:
  • qty: indique le montant de la commande, si ce paramètre n'est pas transmis, le montant de la commande par défaut est utilisé.
  • when: Condition d'exécution, vous pouvez spécifier ce paramètre pour contrôler si l'opération suivante est déclenchée ou non.
  • limitLe prix limite de la commande est indiqué.
  • stopLe prix d'arrêt:

strategy.entryDétails de l'exécutionstrategyLe contrôle des paramètres lors de l'appel d'une fonction peut également être effectué parParamètres de modélisation de la classe de transaction de langue PinePour plus de détails sur les paramètres de configuration et de contrôle de la modélisation de la bibliothèque de classes de transactions en langage Pine, consultez le document ci-dessous.

Je vais vous expliquer pourquoi.strategyDans la fonction,pyramidingdefault_qty_valueParamètres ◦ Test avec le code suivant:

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)

Début du code/*backtest ... */La partie du paquet est un réglage de la rétro-mesure, qui est destiné à enregistrer des informations telles que le temps de réglage de la rétro-mesure à ce moment-là, pour faciliter le débogage, et non le code de stratégie.

Dans le code:strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)Quand nous avons désignépyramidingSi le paramètre est de 3, nous pouvons régler le maximum de 3 transactions dans la même direction. Donc dans l'exemple, 4 fois.strategy.entryL'opération suivante n'a pas été exécutée une fois.default_qty_valueLe paramètre est 0.1, donc l'identifiant de l'ID est long1<unk>strategy.entryLa valeur par défaut de la commande suivante est 0.1.strategy.entryEt nous avons appelé la fonction.directionest égal àstrategy.longLes tests de retour sont payants.

Attention au codestrategy.entry("long3", ...L'opération suivante est appelée deux fois, pour le même ID: <unk>long3<unk>.strategy.entryLa commande suivante n'a pas été exécutée, deuxième appelstrategy.entryLa fonction modifie l'ordre de l'ID ((les données affichées lors du test de retour peuvent également montrer que le montant de l'ordre de plafonnement a été modifié pour 0.3)). Dans un autre cas, par exemple, si l'ordre d'ID a été négocié pour la première fois pour 3 piles de longueur, continuez à utiliser l'ID négocié pour 3 piles de longueur.strategy.entrySi la fonction commande, alors la position de commande s'accumule sur ID<unk>long3<unk>.


2、strategy.close

strategy.closeLa fonction est utilisée pour désigner les positions de placement pour les positions d'entrée identifiées par l'ID. Les principaux paramètres sont:idwhenqtyqty_percent

paramètre:

  • idNous avons besoin d'un identifiant d'accès pour faire un dépôt, et nous l'utilisons.strategy.entryL'ID indiqué lors de l'ouverture de la fonction de commande d'entrée.
  • whenConditions de mise en œuvre:
  • qtyNombre de placements en bourse.
  • qty_percentLe taux d'équilibre est de:

Pour en savoir plus sur l'utilisation de cette fonction, voici un exemple:
Dans le code/*backtest ... */Il s'agit de l'information de configuration de la station internationale FMZ.COM lors du test de retour, qui peut être supprimée, et de l'information sur le marché, la variété, la période de test et d'autres informations dont vous avez besoin.

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 stratégie de test a montré qu'il fallait commencer par faire trois entrées consécutives avec un ID d'entrée de longueur 1 et ensuite utiliserstrategy.closeOn peut trouver les différents résultats de la régression des paramètres de la fonction.strategy.closeCette fonction n'a pas de paramètre pour spécifier le prix de la commande de placement, cette fonction est principalement utilisée pour le placement immédiat au prix du marché actuel.


3、strategy.close_all

strategy.close_allLa fonction est utilisée pour effacer toutes les positions actuelles, car les scripts de langage Pine ne peuvent tenir que dans un seul sens, c'est-à-dire si un signal opposé à la direction de la position actuelle est déclenché, la position actuelle est effacée et la position est déclenchée en fonction du signal.strategy.close_allLa position de l'indicateur est appelée et évacue toutes les positions dans la direction actuelle.strategy.close_allLes principaux paramètres de la fonction sont:when

paramètre:

  • whenConditions de mise en œuvre:

Nous utilisons un exemple pour observer:

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

Le code de test débute avec un portefeuille de 0...strategy.position_size==0est vraie), donc l'exécution de l'ID est à l'emplacement de la colonne de longueur de la colonne de longueur de la colonne de longueur de la colonne de longueurstrategy.entryFonction d'entrée:strategy.position_sizePlus grand que 0, c'est à ce moment-là que la fonction d'entrée ID pour la colonne short peut être exécutée, car il y a actuellement des positions multiples, ce signal de dépréciation inversé qui apparaît à ce moment-là entraînera le dépréciation de la position multiples et la reprise de la vacance. Ensuite, nous écrivons dans la condition if lorsquestrategy.position_size < 0Lorsque le détenteur détient une position à vide, il élimine la totalité de la position détenue dans la direction de la position actuelle.enableStop := true◦ Arrêter l'exécution de la stratégie afin d'observer le journal ◦

On peut trouverstrategy.close_allCette fonction n'a pas de paramètre pour spécifier le prix de la commande de placement, cette fonction est principalement utilisée pour le placement immédiat au prix du marché actuel.


4、strategy.exit

strategy.exitLa fonction est utilisée pour les opérations de placement d'entrée de position. Elle diffère de la fonctionstrategy.closeetstrategy.close_allLa fonction est la liquidation immédiate au prix du marché actuel.strategy.exitLa fonction planifie la compensation en fonction des paramètres.

paramètre:

  • id: L'identifiant de commande de ce bon de placement actuel est l'ID。
  • from_entry: est l'identifiant d'entrée utilisé pour spécifier l'opération de placement.
  • qtyNombre de placements en bourse.
  • qty_percentPourcentage de plafonnement, gamme: 0 ~ 100 ◦
  • profitLes objectifs de profit sont exprimés en points.
  • loss: Objectif d'arrêt des dégâts, exprimé en points.
  • limitLes objectifs de rentabilité sont définis par le prix.
  • stop: cessez-le-feu, indiquez le prix.
  • whenConditions de mise en œuvre:

Utilisez une stratégie de test pour comprendre l'utilisation des paramètres.

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

Cette stratégie de test commence par effectuer 3 opérations d'entrée (par exemple,strategy.entryFonction), qui est délibérément définie par long1limitParamètre, le prix de la commande est de 1 pour l'empêcher de négocier. Ensuite, testez la fonction de sortie de la conditionstrategy.exit❚ Les stop-loss sont utilisés pour le nombre de points, le prix, le nombre de positions, le pourcentage. ❚ Les stop-loss sont également utilisés, étant donné que dans l'exemple d'étendue, les stop-loss sont uniquement représentés.strategy.exitLes fonctions ont aussi des paramètres de suivi et de stop-loss plus complexes:trail_pricetrail_pointstrail_offsetVous pouvez également tester l'apprentissage de l'utilisation dans cet exemple.


5、strategy.cancel

strategy.cancelLes fonctions utilisées pour annuler / désactiver toutes les commandes de la liste de préchargement.strategy.order, strategy.entry , strategy.exitCette fonction peut générer un ID d'entrée. Ses principaux paramètres sont:idwhen

paramètre:

  • idLe nom de la personne qui a été autorisée à entrer dans l'établissement:
  • whenConditions de mise en œuvre:

Cette fonction est très bien comprise, elle est utilisée pour annuler des commandes d'entrée qui n'ont pas été traitées.

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_allFonctions etstrategy.cancelLa fonction est similaire à la fonction <unk> annuler/arrêter toutes les commandes de la liste de pré-enregistrement <unk>.whenParamètres

paramètre:

  • whenConditions de mise en œuvre:
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.orderLes fonctions, les paramètres, etc. sont presque identiques à ceux de la fonction.strategy.entryCohérence, distinction entrestrategy.orderLa fonction n'est pas protégée.strategyLa fonctionpyramidingLes paramètres affectent le nombre de fois que l'appareil peut être téléchargé sans restriction.

paramètre:

  • id: peut être interprété comme un nom donné à une position de négociation pour être utilisé comme référence. Il peut être utilisé comme référence pour l'annulation, la modification de l'ordre, la clôture de position.
  • direction: le paramètre est transmis si la direction de commande est faire plus (acheter)strategy.longCette variable interne est transmise si vous voulez faire une vente à découvert.strategy.shortCette variable:
  • qty: indique le montant de la commande, si ce paramètre n'est pas transmis, le montant de la commande par défaut est utilisé.
  • when: Condition d'exécution, vous pouvez spécifier ce paramètre pour contrôler si l'opération suivante est déclenchée ou non.
  • limitLe prix limite de la commande est indiqué.
  • stopLe prix d'arrêt:

Nous utilisonsstrategy.orderIl n'y a pas de limite au nombre de séquences.strategy.exitLa fonction de sortie conditionnelle ◦ construire un script de transaction similaire à la grille ◦ l'exemple est très simple et est destiné à l'apprentissage seulement:

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)

Exemple de stratégie

Les exemples de stratégies dans ce tutoriel sont utilisés uniquement pour l'enseignement des stratégies, l'orientation des stratégies et la conception des idées, et ne constituent pas une orientation ou une recommandation commerciale. Les stratégies d'enseignement ne sont pas disponibles en ligne.

Stratégie d'indicateur de tendance

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

L'écriture d'une stratégie de tendance dans le langage Pine est très simple, nous avons conçu une stratégie de suivi de tendance simple avec un indicateur de tendance super. Analysons ensemble le code source de cette stratégie.

Le code stratégique est d'abord utiliséstrategyLa fonction fait quelques réglages simples:strategy("supertrend", overlay=true)Il suffit de définir une stratégie intitulée "supertrend".overlayLes paramètres sonttrueNous avons créé une stratégie Pine ou nous avons appris un script de stratégie Pine. La première chose à faire est de regarder la conception des paramètres de l'interface de la stratégie. Nous regardons le code source de "Super Trend Indicator Strategy", qui contient des informations que nous avons apprises dans les cours précédents.inputfonction

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

inputLes appels de fonctions sont directement utilisés pourta.supertrendLes paramètres de la fonction indicateur sont utilisés pour calculer l'indicateur de super-tendance. Parmi ceux-ci:

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

Par défaut, la fonction définit deux contrôles de paramètres dans l'interface de stratégie du langage Pine, comme indiqué ci-dessous:

img

Vous pouvez voir que la valeur par défaut de la commande estinputFonctions etinputLa fonction de séquence estinput.intLes deux fonctions permettent de définir des paramètres sur l'interface de stratégie.ta.supertrendLes paramètres de la fonction sont les suivants:supertrendet une direction de donnéesdirection◦ Puis utilisez-leplotTracez le diagramme fonctionnel, en prenant en compte la direction du diagramme en fonction de l'indicateur de tendance super, et ne tracez que la direction actuelle.directionPour le moment, la tendance actuelle est à la hausse.directionLa tendance actuelle est à la baisse pour 1 heure.plotJ'ai décidé de dessiner une fonction.directionPlus grand que, plus petit que 0 <unk>

Le prochainif ... else ifLa logique est le jugement des signaux de transaction.direction < 0Il s'agit d'une indication en temps réel de l'évolution de la situation actuelle à la hausse, lorsque les données de prix de l'indicateur de tendance supérieuresupertrendLe prix de l'indicateur de tendance super est supérieur au prix de l'indicateur de tendance super sur les 2 BAR précédents (c'est-à-diresupertrend[2],还记得历史操作符引用某个变量历史数据吧Si vous avez une position en cours d'exécution, l'appel de la fonction de commande inverse à ce moment-là effacera la position précédente, puis ouvrira la position en fonction de la direction de la transaction en cours.supertrend > supertrend[2]Les conditions n'ont pas été remplies, à condition questrategy.position_size < 0Le fait de détenir une position vacante peut aussi déclencher des tensions.strategy.close_all()L'exécution de la fonction, effectuant la totalité de la mise en équilibre.

direction > 0C'est la même chose quand on est dans une tendance à la baisse, et si on a plusieurs détenteurs de positions, on est complètement à plat et on est éligible.supertrend < supertrend[3]C'est pourquoi il a été configuré comme suit:[3]Il est possible que les stratèges aient eu l'intention de le faire, car le risque de faire faillite sur certains marchés, comme le marché des contrats, est légèrement supérieur à celui de faire faillite sur d'autres.

pourta.supertrendL'indicateur, est-ce que certains de mes camarades sont intéressés à savoir comment il détermine si la tendance actuelle est à la hausse ou à la baisse ?

En fait, cet indicateur peut également être réalisé sous la forme de fonctions personnalisées dans le langage 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]

Cette fonction est une fonction de base et une fonction de base.ta.supertrendLe même algorithme, et bien sûr les mêmes indicateurs.
Nous pouvons voir, à partir de cet algorithme de fonctionnalité personnalisée, que le calcul de l'indicateur de super-tendance intégré de Pine utilisehl2Variables intégrées ((le prix le plus élevé, le prix le plus bas sont additionnés puis divisés par 2, soit la moyenne du prix le plus élevé et le prix le plus bas), puis calculer l'indicateur ATR d'une période donnée selon le paramètreatrPeriod ((amplitude d'onde)). Puis utiliser hl2 et l'ATR pour construire le haut et le bas de la voie.

Mise à jour en fonction de l'expression triangulaire dans le codelowerBandetupperBand

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

Les bandes inférieures et supérieures sont toujours calculées, mais cette fonction est utilisée pour déterminer la direction de la tendance actuelle.

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

Si le prix de la dernière tendance sur la barre estprevUpperBand, c'est-à-dire la ligne ascendante, indique que la tendance actuelle est à la baisse.closePlus deupperBandLes prix ont atteint un sommet, ce qui signifie que la tendance a été modifiée et qu'elle est devenue une tendance à la hausse.directionLa variable de direction est définie sur -1 (trend à la hausse). Sinon, elle est toujours définie sur 1 (trend à la baisse).if direction < 0Le signal est déclenché lorsque la condition est activée.direction > 0Le signal est déclenché par le déclenchement de la condition de vide.

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

Finalement, des données de prix et de direction sont renvoyées pour des indices de tendance supérieure spécifiques selon la direction choisie.

Stratégie d'équilibre dynamique

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

Nous continuons à étudier quelques exemples de stratégies de conception dans le langage Pine, cette fois nous allons voir une stratégie d'équilibrage dynamique.BaseCurrencyLe montant et le type de transactionQuoteCurrencyLe montant d'une devise est toujours traité en équilibre. Si le prix relatif d'un actif augmente, la valeur détenue dans le compte augmente, quel actif est vendu. Si le prix relatif d'un actif diminue, la valeur détenue dans le compte diminue, achetez cet actif. C'est ce qu'on appelle la stratégie d'équilibre dynamique.

Les inconvénients de cette stratégie sont que, comme le montre le graphique de réévaluation de cette stratégie, la volatilité et la perte de la stratégie sont plus importantes pendant les phases de hausse (ou de baisse) de la tendance des prix. Cette stratégie est donc bonne pour les stratégies en espèces, et l'utilisation des futures nécessite une bonne maîtrise des risques.

Voici un aperçu de la conception du code stratégique:

Nous avons utilisé une conception simplifiée pour simuler unebalance(c'est-à-dire le nombre d'actifs de QuoteCurrency) etstocksNous ne lisons pas le nombre réel d'actifs dans le compte, nous utilisons simplement le montant simulé pour calculer l'achat et la vente appropriés. Les paramètres clés qui influencent la grille de cette stratégie d'équilibrage dynamique sont:maxDiffValue, ce paramètre est le critère de jugement de l'équilibre.BaseCurrencyetQuoteCurrencyLe décalage est supérieur àmaxDiffValueC'est le moment d'équilibrer, de vendre des actifs à prix élevé, d'acheter des actifs à bas prix, de rééquilibrer les actifs.

Le déclenchement d'un signal de négociation stratégique doit avoir un sens au stade BAR en temps réel, de sorte que les conditions de négociation stratégique sont définies dans le jugement ifnot barstate.ishistoryLe prix de l'électricité a été réduit de 30 à 40 dollars par an en fonction des prix actuels.balanceLa valeur dépassestocksOpération d'achat au moment de la valeur. Opération de vente à l'inverse. Mise à jour après exécution de la déclaration de transaction.balanceetstocksLa variable est ensuite déclenchée pour le prochain équilibre.

Les informations ci-dessus contiennent le prix de la variété au début de l'analyse de la stratégie, le prix était de 1458, donc j'ai délibérément défini les paramètresbalanceIl y a aussi le nombre d'étoiles.*3), paramètres de réglagestocksPour: 3. Laisser l'actif en équilibre au début.

Une stratégie de super-tendance avec suivi de stop-loss

Nous avons appris dans les cours précédentsstrategy.exitLa fonction de sortie de position, dont nous n'avons pas d'exemple pour la fonction de suivi et d'arrêt des pertes. Dans cette section, nous utiliserons des exemples de stratégie de conceptionstrategy.exitLes fonctions de suivi et d'arrêt de perte permettent d'optimiser une stratégie de super-tendance.

Nous allons voir.strategy.exitParamètre de la fonction de suivi de la perte de fonction:

1、trail_priceParamètre: Localisation de l'action logique qui déclenche la mise en place d'un blocage de suivi et d'un arrêt de la perte de liquidation de l'échéancier ((à la position spécifiée par le prix))
2、trail_offsetParamètre: la distance entre le prix le plus élevé (le plus élevé) et le prix le plus bas (le plus bas) après l'exécution d'un stop loss tracking.
3、trail_pointsParamètres: commetrail_priceParamètre, mais avec le nombre d'aiguilles pour la position spécifiée.

Si c'est difficile à comprendre, c'est très bien ! Nous allons comprendre l'apprentissage par un scénario de rétrospective stratégique, qui est en fait très simple.

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 stratégie commence à être exécutée immédiatement après l'entrée multi-têtes, puis immédiatement après l'entrée multi-têtes.strategy.exitL'ordre de sortie ((définit le paramètre de stop loss tracking), commence à exécuter la logique de stop loss tracking lorsque la hausse des prix dépasse la ligne de déclenchement de trail_price, le stop loss stop line ((bleu) commence à suivre la dynamique des prix les plus élevés, l'emplacement de la ligne bleue est le prix auquel le stop loss stop stop déclenche l'équilibre, et finalement lorsque le prix de la hausse des prix dépasse la ligne bleue, il déclenche l'équilibre.

Alors nous utilisons cette fonction pour optimiser une stratégie de super-tendance, nous ne donnons qu'un seul ordre d'entrée à la stratégie.strategy.exitLa fonction de suivi et de prévention des dommages peut être ajoutée à la feuille de route.

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

Le code de stratégie complet :

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)