Les ressources ont été chargées... Je charge...

Inventeur d'un didacticiel d'introduction à la langue PINE

Auteur:L'inventeur de la quantification - un petit rêve, Créé à: 2022-05-30 16:23:43, Mis à jour à: 2022-09-28 17:10:21

Voici quelques exemples:

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 importants: l'expression utilisée pour le jugement retourne une valeur de Boole. Attention à la contraction. Il ne peut y avoir qu'une brancheelse au maximum. Toutes les expressions branchées ne sont pas vraies et aucune brancheelse ne retourne na.

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

Puisque lorsque la ligne K BAR est une ligne cintrée, c'est-à-dire lorsque close < open, l'expression après la phrase if est false, le bloc de code local de if n'est pas exécuté. Cette fois non plus, il n'y a pas de brancheelse, la phrase if renvoie na. x est attribué à na.

commutateur

Les statements switch sont également des statements à structure branchée, conçus pour exécuter différents chemins en fonction de certaines conditions. Les statements switch ont généralement les points de connaissances suivants:

Les expressions 1, switch et if renvoient des valeurs. 2) Contrairement aux expressions de commutation dans d'autres langages, l'exécution de la structure de commutation n'exécute qu'un seul bloc local de son code, de sorte qu'une déclaration de break n'est pas nécessaire (c'est-à-dire qu'il n'est pas nécessaire d'écrire des mots clés tels que break). Chaque branche de Switch peut écrire un bloc de code local, dont la dernière ligne est la valeur de retour (elle peut être un élément de valeur). Si aucun bloc de code local branché n'est exécuté, il renvoie na. 4. Déterminer la position d'une expression dans une structure de commutation, écrire des strings, des variables, des expressions ou des appels de fonction. 5. switch permet de spécifier une valeur de retour qui est utilisée comme valeur par défaut lorsqu'aucune autre situation dans la structure n'est exécutée.

Les commutateurs sont divisés en deux types, et nous allons voir un exemple après l'autre pour comprendre comment ils sont utilisés.

1 avec une expressionswitchIl y a aussi des exemples:

// 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 étudié les fonctions d'entrée plus tôt, et nous avons continué à étudier deux fonctions similaires à celles d'entrée:input.stringinput.intLes fonctions.input.stringIl y a un autre moyen de retourner les chaînes.input.intLa fonction est utilisée pour renvoyer une valeur entière.optionsLes paramètres sont utilisés.optionsLes paramètres peuvent être passés dans une matrice composée de valeurs sélectionnables.options=["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). Ainsi, les contrôles de l'interface de stratégie n'ont pas besoin d'entrer de valeur spécifique, mais deviennent un menu déroulant pour sélectionner les options fournies dans le paramètre options.

La valeur de la variable func est une chaîne, la variable func est utilisée comme expression de la commutation (peut être une variable, un appel à une fonction, une expression) pour déterminer quelle branche de la commutation est exécutée. Si la variable func ne correspond pas à l'expression de n'importe quelle branche de la commutation (c'est-à-dire est égale), la branche par défaut est exécutée.runtime.error("error")Les fonctions provoquent l'arrêt exceptionnel de la stratégie.

Dans notre code de test ci-dessus, nous n'avons pas ajouté de code tel que [na, na] après la dernière ligne du bloc de code de branche par défaut de Switch pour rendre la valeur de compatibilité, ce qui nécessite de considérer le problème en vue du trading, si le type n'est pas cohérent. Mais dans FMZ, il est possible d'ignorer ce code de compatibilité car il n'y a pas de type strictement requis.

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 dans FMZ, mais il y en a dans Trading View.

Il n'y a pas d'expressionswitch

Nous allons voir.switchL'autre façon d'utiliser le terme est d'écrire sans expression.

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)

On peut voir dans l'exemple de code de test que le switch correspond à un bloc de code local vrai sur la condition d'exécution d'une branche. En général, les conditions de branche après la déclaration du switch doivent être réciproques. C'est-à-dire que dans l'exemple, up et down ne peuvent pas être vrais à la fois.up = close > open // up = close < openAu lieu de remplacer le contenu dans les notes, réessayez d'observer le résultat. Vous constaterez que la branche de switch ne peut exécuter que la première branche.switchDans l'exemple "Executive branch" la branche d'exécution est définie et n'est pas modifiée au cours de l'exécution de la stratégie).

Structure cyclique

Le for

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

L'utilisation de l'instruction for est très simple, car le cycle for peut finalement renvoyer une valeur ((ou plusieurs valeurs, sous la forme de [a, b, c])); comme dans le pseudo ci-dessus, l'attribution d'une variable à la position de "valeur de retour". Une variable de "compte" est suivie d'une instruction for pour contrôler le nombre de cycles, citer d'autres valeurs, etc. La variable "compte" est attribuée au "compte initial" avant le début du cycle, puis est passée en fonction de la configuration "croissance", le cycle s'arrête lorsque le nombre de "compte" est supérieur à "variable final".

Pour la circulationbreakMots clés: Quand cela est faitbreakAprès une phrase, le cycle s'arrête. Pour la circulationcontinueMots clés: Quand cela est faitcontinueAprès une phrase, le cycle est ignoré.continueLe code suivant, exécute directement le prochain cycle. La déclaration for renvoie la valeur de retour lors de l'exécution du dernier cycle. Si aucun code n'est exécuté, elle renvoie une valeur vide.

Voici un exemple simple pour le montrer:

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... en phrases

for ... inIl existe deux formes de phrases, illustrées par le pseudo-code ci-dessous.

返回值 = 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, l'une étant l'utilisation d'une variable comme référence à un élément d'une matrice. L'autre est l'utilisation d'une structure contenant une variable d'index, un élément d'une matrice.

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'index quand vous en avez besoin.for [i, ele] in testArrayIl est écrit comme ça:

pour les applications cyclables

Lorsque des calculs de logique circulaire peuvent être effectués à l'aide des fonctions intégrées fournies par le langage Pine, il est possible d'écrire directement à l'aide de structures circulaires ou de traiter les fonctions intégrées. Nous en donnons deux exemples.

1 est la moyenne.

Pour la conception de structures circulaires:

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 circulaire for, puis on calcule l'égalité.

Comptez directement l'équation en utilisant la fonction intégrée:

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

Utilisez directement les fonctions intégréesta.smaLe calcul de l'indicateur homogène est évidemment plus simple pour le calcul de l'homogénéité en utilisant des fonctions intégrées.

2 et plus

L'exemple ci-dessus peut être utilisé comme exemple.

Pour la conception de structures circulaires:

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 tous les éléments d'une matrice et qui peuvent être traités en utilisant le cycle, on peut également utiliser des fonctions intégrées.array.sumIl y a des gens qui sont en train de calculer. Calculer la somme directement à l'aide des fonctions intégrées:

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)

Les données calculées peuvent être vues comme étant parfaitement cohérentes sur le graphique à l'aide d'un diagramme.

Alors, si ces tâches peuvent être accomplies avec des fonctions intégrées, pourquoi concevoir des cycles? 1, quelques opérations pour les arithmétiques, calculer. 2° Revenir sur l'histoire, par exemple, pour savoir combien de pics passés sont supérieurs à ceux du BAR actuel. Puisque les pics du BAR actuel ne sont connus que dans le BAR où le script est exécuté, un cycle est nécessaire pour revenir en temps opportun et analyser le BAR passé. 3, lorsque les fonctions intégrées utilisant le langage Pine ne peuvent pas compléter le calcul du passé BAR.

Le mot while

whileLes statements permettent au code de la partie circulaire d'être exécuté jusqu'à ce que la condition de jugement dans la structure while soit 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 boucle est une valeur de retour, qui peut renvoyer plusieurs valeurs.

Je vais vous montrer l'exemple d'une ligne horizontale:

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 du while loop est également très simple, mais il est possible de concevoir des logiques de calcul qui ne peuvent pas être remplacées par des fonctions intégrées, telles que calculer des multiples:

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

Ensemble

Les définitions d'une matrice dans le langage Pine sont similaires à celles des autres langages de programmation. Une matrice dans le langage Pine est une matrice en une dimension. Elle est généralement utilisée pour stocker une série de données en continu. Une matrice dans laquelle des données individuelles sont stockées est appelée élément d'une matrice.[]Nous avons besoin d'utiliserarray.get()etarray.set()Fonction. L'ordre d'indexation des éléments d'une matrice est tel que l'indexation du premier élément est 0, l'indexation du prochain élément augmente de 1.

Nous avons utilisé un code simple pour expliquer:

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éclarations

Utilisationarray<int> afloat[] bUne grille déclarée ou une variable déclarée peut être attribuée à une grille, par exemple:

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'initialisation des variables d'une matricearray.newetarray.from函数。Pine语言中还有很多和类型相关的与array.new类似的函数:array.new_int()array.new_bool()array.new_color()array.new_string()Je ne sais pas.

Le mot-clé var peut également fonctionner avec le mode de déclaration de l'array, l'array qui utilise le mot-clé var n'est initialement initialisé que sur le premier BAR. Nous observons ceci par un exemple:

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 d'une matrice a sont constamment fixées et ne sont pas réinstallées. Les matrices b sont initiales à chaque BAR.barstate.islastIl n'y a toujours qu'un seul élément à imprimer en temps réel, une valeur de 0.

Lire et écrire des éléments dans une matrice

Utilisez array.get pour obtenir un élément dans une matrice dont la position est indiquée par l'index, et modifiez l'élément dans une matrice dont la position est indiquée par l'index avec array.set.

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

Pour illustrer cela, on peut utiliser l'exemple suivant:

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 la couleur de base vert, déclare et initie une matrice pour conserver la couleur, puis attribue une transparence différente à la valeur de couleur (en utilisant la fonction color.new). Le rangement de couleur est calculé en calculant la distance maximale de la valeur high au cours des 100 cycles de revue actuels BAR. Plus la distance est proche de la valeur maximale high au cours des 100 cycles de revue récents, plus le rangement est élevé, plus la valeur de couleur correspondante est profonde (la transparence est faible).

Parcourir les éléments d'une matrice

Comment traverser une arithmétique peut être réalisé avec les phrases for/for in/while que nous avons apprises précédemment.

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")
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")
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 navigation donnent les mêmes résultats.

L'arithmétique peut être déclarée à l'échelle globale du script, ou à l'échelle locale de la fonction ou de la branche if.

Citation historique

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

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)

Ajout d'arrayés, suppression d'opérations

Les fonctions liées à l'augmentation des opérations de l'arithmétique 1.

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

Les fonctions liées à l'opération de suppression de l'arithmétique 2.

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

Nous avons utilisé l'exemple suivant pour tester les fonctions d'ajout et de suppression d'opérations de ces matrices.

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

Applications d'ajout et de suppression: Arrays comme queue

Nous pouvons construire une structure de données "queue" à l'aide d'une matrice, ainsi que des fonctions d'ajout et de suppression d'une matrice. Les queues peuvent être utilisées pour calculer les moyennes mobiles des prix des ticks.

Une file d'attente est une structure couramment utilisée dans le domaine de la programmation.

Le premier élément à entrer dans la file d'attente, le premier à sortir de la file d'attente.

Cela permet de s'assurer que les données présentes dans la file d'attente sont les plus récentes et que la longueur de la file d'attente ne s'élargit pas à l'infini.

Dans l'exemple ci-dessous, nous utilisons une structure de file d'attente pour enregistrer le prix de chaque tick, calculer la moyenne mobile au niveau du tick, puis la comparer à la moyenne mobile observée au niveau de la ligne K en 1 minute.

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

Remarquez que nous avons spécifié le mode de déclaration en utilisant le mot-clévaripAinsi, chaque variation de prix est enregistrée dans une matrice a.

calculs arithmétiques couramment utilisés, fonctions d'opération

Calculer les fonctions:

array.avg()La moyenne de tous les éléments de l'arithmétique.array.min()Le plus petit élément de l'arithmétiquearray.max()L'élément le plus grand de l'arithmétique.array.stdev()L'erreur de référence de tous les éléments d'une matrice est la différence de référence de tous les autres éléments.array.sum()La somme de tous les éléments de l'ensemble des nombres.

Fonctions liées à l'opération:array.concat()Combinez ou connectez deux matrices.array.copy()Répliquer une matrice.array.joinConnectez tous les éléments de l'array en une seule chaîne.array.sort()L'ordre de l'article est classé par ordre d'ascension ou de descente.array.reverse()L'inverse de l'arithmétique.array.slice()On coupe les matrices.array.includes()Il est important de savoir ce qui se passe.array.indexof()Retourne l'index dans lequel la valeur d'un paramètre est apparue pour la première fois. Si la valeur n'est pas trouvée, renvoie −1.array.lastindexof()Trouvez la valeur qui est apparue la dernière fois.

Exemples de tests de calcul arithmétique des fonctions connexes:

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 arithmétiques les plus couramment utilisées.

Exemples d'opérations avec des fonctions:

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

Les fonctions

Fonctions personnalisées

Le langage Pine peut concevoir des fonctions personnalisées. En général, les fonctions personnalisées du langage Pine ont les règles suivantes:

1, toutes les fonctions sont définies dans l'échelle globale du script. Une fonction ne peut pas être déclarée dans une autre fonction. 2° Ne pas autoriser les fonctions à s'appeler elles-mêmes dans leur propre code. 3, en principe, toutes les langues PINE ont une fonction graphique intégréebarcolor()、 fill()、 hline()、plot()、 plotbar()、 plotcandle()) ne peut pas être appelé dans une fonction personnalisée. 4, les fonctions peuvent être écrites en une seule ligne, plusieurs lignes. La valeur de retour de la dernière phrase est la valeur de retour de la fonction actuelle, qui peut être retournée sous forme d'éléments.

Nous avons utilisé des fonctions personnalisées plusieurs fois dans les tutoriels précédents, par exemple en créant des fonctions personnalisées en une seule ligne:

barIsUp() => close > open

Cette fonction renvoie si le BAR actuel est le rayon solaire.

Il est conçu comme une fonction personnalisée à plusieurs lignes:

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)

Une fonction calculée par une moyenne SMA que nous avons réalisée nous-mêmes avec des fonctions personnalisées.

Il est également possible de retourner l'exemple d'une fonction personnalisée avec deux variables:

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 l'EMA.

Fonction intégrée

Les fonctions intégrées sont faciles à utiliser.FMZ PINE Script est un fichierJe ne suis pas d'accord avec toi.

Les fonctions intégrées dans le langage Pine:

1, fonction de traitement de chaînestr.La série. 2, fonction de traitement des valeurs de couleurcolor.La série. 3, fonction d'entrée de paramètresinput.La série. 4, fonction de calcul des indicateursta.La série. 5, fonction de dessinplot.La série. 6, fonction de traitement d'arithmétiquearray.La série. 7. Fonctions liées aux transactionsstrategy.La série. 8. Fonctions mathématiquesmath.Une série. 9, autres fonctions (traitement du temps, fonctions de dessin de séries non-plots,request.Les fonctions de série, les fonctions de traitement de type, etc.)

Fonction de transaction

strategy.Les fonctions de série sont des fonctions que nous utilisons souvent dans les stratégies de conception, qui sont étroitement liées à l'exécution des opérations de transaction lorsque la stratégie est spécifiquement exécutée.


1、strategy.entry

strategy.entryLa fonction est une fonction sous-jacente qui est plus importante lorsque nous écrivons des stratégies, et qui a plusieurs paramètres plus importants:id, direction, qty, whenJe ne sais pas.

Paramètres:

  • id: peut être compris comme une référence au nom d'une position de négociation.
  • direction: si la direction de la commande est plus (acheter) le paramètre est transmisstrategy.longCette variable intégrée est transmise si vous voulez faire un sale.strategy.shortCette variable.
  • qty: spécifier la quantité à commander, si ce paramètre n'est pas transmis, la quantité à commander par défaut est utilisée.
  • when: Conditions d'exécution, vous pouvez spécifier ce paramètre pour contrôler si cette opération est déclenchée.
  • limitLe prix de la commande est fixé par le site: WEB
  • stopLe prix de vente est le même.

strategy.entryLes détails d'exécution spécifiques de la fonctionstrategyLes paramètres de contrôle lors de l'appel de la fonction peuvent également être contrôlés par"Paramètres du modèle de la bibliothèque de langues Pine"Pour plus de détails sur la configuration des contrôles, voir la documentation ci-jointe.

Je vais vous expliquer les points principaux.strategyDans la fonction,pyramidingdefault_qty_valueParamètres. Testez en utilisant le code suivant:

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

Le début du code/*backtest ... */La partie du paquet est réglée pour la réévaluation, afin de documenter des informations telles que l'heure de la réévaluation à ce moment-là, pour faciliter le débogage, et non le code de stratégie.

Le code est:strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)Et quand on désignepyramidingSi le paramètre est 3, nous avons un maximum de trois transactions dans la même direction. Donc quatre fois dans l'exemple.strategy.entryUne des opérations ci-dessous n'a pas été exécutée.default_qty_valueLe paramètre est 0.1, donc l'identifiant ID est le long de 1 tonne cette fois.strategy.entryLa valeur de la sous-liste de l'opération est définie par défaut à 0.1 ∞.strategy.entryC'est la fonction que nous avons désignée pour appeler.directionIls sont tous égaux.strategy.longLes tests de réévaluation sont payants.

Attention au code.strategy.entry("long3", ...L'opération suivante est appelée deux fois, pour le même ID: long3.strategy.entryL'opération suivante n'a pas été effectuée, appelée une deuxième foisstrategy.entryLes données affichées lors du retest peuvent également indiquer que la quantité de commande sous cette commande limitée a été modifiée pour 0.3). Dans un autre cas, par exemple, si la première commande pour l'ID de 3 tonnes a été passée, continuez à l'utiliser selon cette commande.strategy.entrySi la fonction passe une commande, toutes les positions seront cumulées sur l'ID de la longueur de 3 bits.


2、strategy.close

strategy.closeLa fonction est utilisée pour spécifier l'ID de l'entrée de placement. Les principaux paramètres sont:idwhenqtyqty_percent

Paramètres:

  • idNous utilisons des identifiants de connexion qui nécessitent un identifiant de mise sur le marché.strategy.entryL'ID indiqué lors de l'ouverture d'une fonction unique.
  • whenLes conditions de mise en œuvre:
  • qtyLe nombre d'offres.
  • qty_percentLe résultat de cette enquête est le suivant:

Pour vous familiariser avec le fonctionnement de cette fonction, voici un exemple: Dans le code/*backtest ... */是FMZ.COM国际站回测时的配置信息,可以删掉,设置自己需要测试的市场、品种、时间范围等信息。

/*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 montre qu'il est possible de commencer à effectuer plusieurs entrées trois fois de suite avec un ID d'entrée de 1 tonne, puis d'utiliserstrategy.closeDifférents résultats sont obtenus lorsque les différents paramètres de la fonction sont réglés en équilibre.strategy.closeCette fonction n'a pas de paramètre permettant de spécifier le prix de l'ordre de mise en liquidation. Elle est principalement utilisée pour la mise en liquidation immédiate au prix du marché actuel.


3、strategy.close_all

strategy.close_allLa fonction est utilisée pour aplanir toutes les positions actuelles, car le script de la langue Pine ne peut aplanir que dans une seule direction, c'est-à-dire qu'il aplanit la position actuelle en fonction du déclenchement d'un signal contraire à la direction actuelle de la position.strategy.close_allLes positions en direction de l'aéroport sont appelées à égaler toutes les positions dans la direction actuelle.strategy.close_allLes principaux paramètres de la fonction sont:when

Paramètres:

  • whenLes conditions de mise en œuvre:

Nous avons utilisé un exemple pour observer:

/*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 

Au début du code de test, le stock est de 0 (c'est à direstrategy.position_size==0Si le paramètre when est correct, alors le paramètre when est correct, mais si le paramètre when est correct, alors le paramètre when est correct.strategy.entryFonction d'entrée. Après avoir détenu plusieurs positionsstrategy.position_sizeSi l'ID est supérieur à 0, la fonction d'entrée de l'étalon de short peut être exécutée. En raison de l'existence de plusieurs positions, le signal de revers d'emplacement qui apparaît à ce moment-là entraînera une élimination des positions multiples.strategy.position_size < 0Lorsque vous avez une position vide, la position totale de la direction actuelle est égalée; et marquezenableStop := true◦ Arrêter l'exécution de la politique pour faciliter l'observation des journaux.

Vous pouvez trouverstrategy.close_allCette fonction n'a pas de paramètre permettant de spécifier le prix de l'ordre de mise en liquidation. Elle est principalement utilisée pour la mise en liquidation immédiate au prix du marché actuel.


4、strategy.exit

strategy.exitLa fonction est utilisée pour les opérations de mise en place des positions d'entrée, mais elle est différente de la fonctionstrategy.closeetstrategy.close_allLes fonctions sont immédiatement liquidées au prix du marché actuel.strategy.exitLa fonction planifie l'équilibrage en fonction des paramètres.

Paramètres:

  • id: l'identifiant d'ordre de la liste de conditions de mise en liquidation actuelle.
  • from_entry: est utilisé pour spécifier l'ID de connexion pour effectuer une opération de mise en place.
  • qtyLe nombre d'offres.
  • qty_percent: pourcentage de l'équilibre, plage: 0 à 100.
  • profitLes objectifs de profit sont indiqués par un nombre de points.
  • lossLe nombre de points indiqué est celui de l'objectif de stop-loss.
  • limitLes objectifs de profit sont indiqués par le prix.
  • stopLes prix sont indiqués par le prix de vente.
  • whenLes conditions de mise en œuvre:

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

/*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 a commencé par exécuter trois opérations d'entrée en utilisant le test de rétrospection du modèle de prix en temps réel.strategy.entryfonction), le long de 1 est délibérément définilimitParamètres, prix de l'ordre de vente est de 1 pour empêcher la transaction. Ensuite, tester la condition de sortie de la fonctionstrategy.exit⇒ On utilise le stop par point, le stop par prix, on utilise le nombre fixe de positions, on utilise le stop par pourcentage. D'autant que l'exemple ci-dessus ne démontre que le stop.strategy.exitLa fonction comporte également des paramètres de suivi plus complexes:trail_pricetrail_pointstrail_offsetVous pouvez également essayer d'apprendre à l'utiliser dans cet exemple.


5、strategy.cancel

strategy.cancelLes fonctions sont utilisées pour annuler / désactiver toutes les commandes des listes en attente.strategy.order, strategy.entry , strategy.exitIl est possible de générer un identifiant de connexion.idwhen

Paramètres:

  • idIl y a aussi une autre version de la vidéo:
  • whenLes conditions de mise en œuvre:

Cette fonction est bien comprise, car elle est utilisée pour annuler les commandes de connexion sans transaction.

/*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_allLes fonctions etstrategy.cancelFonction similaire: ʽannuler/désactiver toutes les commandes prépayées‛whenParamètres.

Paramètres:

  • whenLes conditions de mise en œuvre:
/*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.strategy.entryLe problème est que les gens ne comprennent pas.strategy.orderLes fonctions ne sont passtrategyLa fonctionpyramidingLes paramètres affectent les paramètres, il n'y a pas de limite au nombre de fois suivantes.

Paramètres:

  • id: peut être compris comme une référence au nom d'une position de négociation.
  • direction: si la direction de la commande est plus (acheter) le paramètre est transmisstrategy.longCette variable intégrée est transmise si vous voulez faire un sale.strategy.shortCette variable.
  • qty: spécifier la quantité à commander, si ce paramètre n'est pas transmis, la quantité à commander par défaut est utilisée.
  • when: Conditions d'exécution, vous pouvez spécifier ce paramètre pour contrôler si cette opération est déclenchée.
  • limitLe prix de la commande est fixé par le site: WEB
  • stopLe prix de vente est le même.

Nous utilisonsstrategy.orderIl n'y a pas de limite à cette propriété.strategy.exitFonction de sortie conditionnelle ─ construire un script similaire à une transaction de grille ─ exemple très simple, uniquement pour apprendre:

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

Le modèle stratégique

Les exemples de stratégies dans ce tutoriel sont uniquement utilisés pour les stratégies pédagogiques, les idées de conception de stratégies de guidage, et ne font aucun type de conseils, de conseils et de conseils commerciaux.

La stratégie des indicateurs de tendance

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

Il est très simple d'écrire une stratégie de tendance en utilisant le langage Pine, ici nous avons conçu une stratégie de suivi de tendance simple avec un indicateur de tendance super.

La première chose à faire est d'utiliser le code stratégique.strategyLa fonction fait quelques réglages simples:strategy("supertrend", overlay=true), il suffit de définir une stratégie intitulée Supertrend.overlayLe paramètre esttrueLa première chose que nous faisons pour concevoir une stratégie Pine ou pour apprendre un script de stratégie Pine est de regarder la conception des paramètres de l'interface de stratégie. Nous regardons le code source de la stratégie de l'indicateur de super-tendance, qui contient des choses que nous avons apprises dans des cours précédents.inputLes fonctions

[supertrend, direction] = ta.supertrend ((input ((5, facteur),input.int(Période de référence)

inputL'appel à la fonction est utilisé directement pourta.supertrendLes paramètres de la fonction indicateur sont utilisés pour calculer les indicateurs de supertrend. Parmi eux:

  • l'entrée ((5, facteur)
  • input.int(Période de référence)

Par défaut, la fonction définit deux contrôles de paramètres dans l'interface de stratégie de la langue Pine, comme suit:

img

Vous pouvez voir que la valeur par défaut de la commande estinputLes fonctions etinputLes fonctions de série ((ici) sontinput.intCes deux fonctions nous permettent de définir sur l'interface stratégique.ta.supertrendParamètres de la fonction. La fonction d'indicateur de super-tendance calcule une donnée de prix.supertrendet les données dans une direction.directionJe ne sais pas comment faire.plotGraphique de fonction, notez que lorsque le graphique est dessiné, il est dessiné en fonction de la direction de l'indicateur de supertrend et ne dessine que la direction actuelle; lorsquedirectionLa tendance actuelle du marché est à la hausse à -1 heure, alors que la tendance actuelle du marché est à la hausse à 1 heure.directionLa tendance actuelle du marché est à la baisse à 1 heure.plotDéterminez quand une fonction est dessinée.directionPlus ou moins que 0.

Le prochainif ... else ifLa logique est le jugement du signal de transaction, quand l'expressiondirection < 0L'indicateur de tendance est un indicateur en temps réel indiquant que le marché est en hausse et que si les données de prix dans l'indicateur de tendance supérieure sont supérieures à celles de l'indicateur de tendance supérieure, les prix seront supérieurs à ceux de l'indicateur de tendance supérieure.supertrendPlus élevé que le prix de l'indicateur de la super-tendance sur les 2 premières barres (c'est-à-diresupertrend[2],还记得历史操作符引用某个变量历史数据吧Vous vous souvenez? Si vous avez une position en cours, un appel à la fonction descendante inverse vous permettra d'aplanir la position précédente et d'ouvrir la position en fonction de la direction de la transaction en cours.supertrend > supertrend[2]Les conditions ne sont pas réunies, à condition que ce soit pour le moment.strategy.position_size < 0Il y a aussi la possibilité d'utiliser des appareils de surveillance pour contrôler les mouvements de l'air.strategy.close_all()L'exécution de la fonction, effectuant toutes les opérations d'équilibrage.

direction > 0C'est la même chose lorsque vous êtes dans la phase de tendance à la baisse, si vous avez plusieurs titres qui sont tous en équilibre, alors vous remplissez les conditions.supertrend < supertrend[3]Si vous utilisez le bouton de déclenchement de l'alarme, pourquoi le configurer comme ceci?[3]Qu'en est-il des données sur les prix de l'indicateur de supertrend sur la troisième barre avant? Peut-être que c'est intentionnel pour le stratège, car certains marchés, comme le marché des contrats, sont légèrement plus à risque que les marchés à risque.

Pourta.supertrendL'indicateur, si certains de vos camarades sont intéressés, c'est de savoir comment vous pouvez déterminer si la tendance actuelle est à la hausse ou à la baisse.

En fait, ce paramètre peut également être réalisé sous la forme d'une fonction personnalisée dans le langage 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]

C'est une fonction personnalisée.ta.supertrendL'algorithme est identique, bien sûr, les données d'indicateurs sont les mêmes. On peut voir à partir de cet algorithme de fonctionnalités personnalisées que le calcul des indicateurs de super-tendance intégrés de Pine est utilisé parhl2La variable intégrée (le prix le plus élevé, le prix le plus bas, le prix le plus élevé, le prix le plus bas, le prix le plus élevé, le prix le plus bas, le prix le plus élevé, le prix le plus bas, le prix le plus élevé, le prix le plus bas, le prix le plus élevé, le prix le plus bas, le prix le plus élevé, le prix le plus bas, la valeur moyenne du prix le plus élevé, le prix le plus bas) est calculée en fonction du paramètre atPeriod.

Mise à jour en fonction des expressions triangulaires dans le codelowerBandetupperBand

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

lowerBand: ligne descendante, pour déterminer si la tendance ascendante a changé; upperBand: ligne descendante, pour déterminer si la tendance descendante a changé; lowerBand et upperBand sont toujours en cours de calcul, mais cette fonction personnalisée détermine finalement la direction de la tendance actuelle.

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

On peut voir ici si la valeur de la super tendance sur la dernière barre estprevUpperBandLa tendance à la baisse est indiquée par la ligne ascendante.closePlus queupperBandLes prix ont évolué et ont été transformés en tendance haussière.directionLa variable de direction est définie sur - (Tendance haussière) ; sinon elle reste définie sur 1 (Tendance baissière).if direction < 0Les conditions du signal ont été déclenchées.direction > 0Les conditions du signal ont été déclenchées et le signal est resté vide.

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

Enfin, les données relatives aux prix et aux orientations des indicateurs de supertrend spécifiques sont retournées selon la direction choisie.

Stratégie d'équilibrage dynamique

/*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 avons continué à étudier quelques exemples de conception de stratégies dans le langage Pine, mais cette fois nous avons vu une stratégie de balancement dynamique.BaseCurrencyLe montant et la variété de la transactionQuoteCurrencyLe montant de la monnaie est toujours traité en équilibre. Le prix relatif d'un actif augmente et la valeur du compte augmente. Si le prix relatif d'un actif diminue et la valeur du compte diminue, l'actif est acheté. C'est ce qu'on appelle la stratégie d'équilibrage dynamique.

Les inconvénients de cette stratégie sont que, comme le montre le graphique de retrospective, la stratégie de flottaison est plus importante lors de la phase de forte hausse (ou forte baisse) des prix.

Nous allons voir la stratégie de conception du code:

Nous avons utilisé une conception simplifiée pour simuler dans la stratégie unebalance(c'est-à-dire le nombre d'actifs en devises) etstocksNous n'allons pas lire le nombre réel d'actifs dans le compte, nous utilisons simplement des montants simulés pour calculer les achats et les ventes appropriés.maxDiffValueCe paramètre est le critère de jugement d'équilibre.BaseCurrencyetQuoteCurrencyLa déviation est plus grandemaxDiffValueIl est temps d'équilibrer, de vendre des actifs plus chers, d'acheter des actifs moins chers et de rééquilibrer les actifs.

Le déclenchement du signal de trading stratégique doit avoir un sens à la phase BAR en temps réel, donc les conditions de trading stratégique sont mises en place dans le jugement if.not barstate.ishistoryLes prix actuels ne sont pas très élevés.balanceLa valeur dépassestocksOpération d'achat lors de la valeur. Opération de vente à l'inverse. Mise à jour après l'exécution de la transaction.balanceetstocksIl y a une différence entre les deux types d'équilibre.

L'information ci-dessus contient le prix de la variété au début de l'analyse stratégique, qui est de 1458, donc j'ai délibérément défini le paramètrebalanceParamètres définis pour: 4374 ((1458*3)stocksPour: 3° maintenir l'actif en équilibre au début.

Une stratégie de super-trend avec un suivi des pertes et des pertes

Dans les cours précédents, nous avons apprisstrategy.exitNous n'avons pas d'exemples pour les fonctions de sortie de position, dont la fonction de suivi de l'arrêt de la perte. Nous utilisons les exemples de conception de stratégie dans cette section.strategy.exitLa fonction de suivi stop-loss stop-loss fonctionne pour optimiser une stratégie de super-trend.

Tout d'abord, voyons.strategy.exitLes paramètres de la fonction Tracking Stop Loss Stop:

1、trail_priceParamètres: déclencheur pour placer le suivi de l'ordre de mise en place logique de l'ordre de mise en place (à un prix spécifié)


Plus de