Also sehen wir, dass in den gezeichneten drei Linien a, b und c, Linie b ist ein BAR langsamer als Linie a, und Linie c ist ein BAR langsamer als Linie b. Linie c ist 2-BAR langsamer als Linie a.
Wir können das Diagramm nach links ziehen und beobachten, dass auf der ersten K-Linie beide Werte von b und c null (na) sind. Dies liegt daran, dass das Skript, wenn es auf der ersten K-Linie BAR ausgeführt wird, nicht existiert, wenn man sich auf den historischen Wert von ein oder zwei Perioden nach vorne bezieht, der nicht existiert. Daher müssen wir beim Schreiben von Strategien vorsichtig sein, um zu überprüfen, ob das Verweisen auf historische Daten zu Nullwerten führt. Wenn der Nullwert unvorsichtig verwendet wird, verursacht dies eine Reihe von Berechnungsunterschieden und kann sogar den Echtzeit-BAR beeinflussen. Normalerweise verwenden wir integrierte Funktionenna
, nz
Das ist eine sehr schwierige Frage, die wir uns stellen müssen.nz
, ```na`` in unseren vorherigen Videos, erinnern Sie sich, welches Kapitel es ist?) beschäftigen sich mit dem Fall von Nullwerten, zum Beispiel:
close > nz(close[1], open) // When referencing the historical value of the previous BAR of the close built-in variable, if it does not exist, the open built-in variable is used
Dies ist eine Möglichkeit, mögliche Verweise auf Nullwerte (na) zu behandeln.
Wir haben viele Operatoren in der Pine-Sprache gelernt. Diese Operatoren bilden Ausdrücke durch verschiedene Kombinationen mit Operanden. Was ist also die Priorität dieser Operationen bei der Auswertung in Ausdrücken? Genau wie die Arithmetik, die wir in der Schule gelernt haben, werden Multiplikation und Division zuerst berechnet, gefolgt von Addition und Subtraktion. Das gleiche gilt für Ausdrücke in der Pine-Sprache.
Priorität | Betreiber |
---|---|
9 | [] |
8 | + 、- undnot in der unarischen Operator |
7 | * 、/ 、% |
6 | + 、- im Binäroperator |
5 | > 、< 、>= 、<= |
4 | == 、!= |
3 | and |
2 | or |
1 | ?: |
Wenn Sie ein bestimmtes Teil zuerst bewerten wollen, können Sie()
um den Ausdruck zu wickeln, um den Teil zu zwingen, der zuerst ausgewertet werden soll.
Wir haben bereits das Konzept von
Anmeldemodus:
Das erste, was beim Deklarieren einer Variable geschrieben wird, ist der
var
.varip
.Dievar
undvarip
Schlüsselwörter wurden in unserem vorherigen KapitelAssignment Operators
Wenn nichts für den Variablendeklarationsmodus geschrieben wird, wie z.B. die Anweisung:i = 1
, wie bereits erwähnt, wird eine solche Variable, die deklariert und zugewiesen wird, auf jeder K-Line BAR ausgeführt.
Typ Die Pine-Sprache auf FMZ ist nicht streng hinsichtlich der Typen und kann im Allgemeinen weggelassen werden.
int i = 0
float f = 1.1
Die Typanforderungen für die Trading-Ansicht sind recht streng, und ein Fehler wird gemeldet, wenn der folgende Code in der Trading-Ansicht verwendet wird:
baseLine0 = na // compile time error!
Markierung Marker sind Variablennamen. Die Benennung von Markern wurde in früheren Kapiteln erwähnt, so dass Sie es hier überprüfen können:https://www.fmz.com/bbs-topic/9637#markers
Zusammenfassend lässt sich die Erklärung einer Variablen wie folgt schreiben:
// [<declaration_mode>] [<type>] <marker> = value
declaration mode type marker = value
Der Zuweisungsoperator wird hier verwendet:=
Beim Zuordnen kann der Wert eine Zeichenfolge, eine Zahl, ein Ausdruck, ein Funktionsanruf sein,if
, for
, while
, oderswitch
und andere Strukturen (diese strukturellen Schlüsselwörter und Statement-Nutzung werden in den folgenden Kursen ausführlich erläutert.
Hier konzentrieren wir uns auf die Eingabefunktion, die wir häufig bei der Gestaltung und Erstellung von Strategien verwenden.
Eingabefunktion:
input function, parameters: defval、title、tooltip、inline、group
Die Eingabefunktion auf FMZ unterscheidet sich etwas von der auf Trading View, aber diese Funktion wird als Zuweisungseingabe von Strategieparametern verwendet.
param1 = input(10, title="name of param1", tooltip="description for param1", group="group name A")
param2 = input("close", title="name of param2", tooltip="description for param2", group="group name A")
param3 = input(color.red, title="name of param3", tooltip="description for param3", group="group name B")
param4 = input(close, title="name of param4", tooltip="description for param4", group="group name B")
param5 = input(true, title="name of param5", tooltip="description for param5", group="group name C")
ma = ta.ema(param4, param1)
plot(ma, title=param2, color=param3, overlay=param5)
Die Eingabefunktion wird häufig verwendet, um Variablen beim Deklarieren von Werten zuzuweisen. Die Eingabefunktion auf FMZ zieht Steuerelemente für die automatische Einstellung von Strategieparametern in der FMZ-Strategieoberfläche. Die auf FMZ unterstützten Steuerelemente umfassen derzeit numerische Eingabefelder, Text-Eingabefelder, Dropdown-Boxen und booleanische Kontrollkästchen. Und Sie können die Gruppierung von Strategieparametern, die Einstellung der Parameter-Aufforderungsschrift und andere Funktionen festlegen.
Wir stellen einige Hauptparameter der Eingabefunktion vor:
Zusätzlich zur Erklärung und Zuordnung einzelner Variablen gibt es auch eine Möglichkeit, eine Gruppe von Variablen zu deklarieren und in der Pine-Sprache zuzuweisen:
[Variable A, Variable B, Variable C] = function or structure, such as ```if```, ```for```, ```while``` or ```switch```
Die häufigste ist, wenn wir dieta.macd
Da der MACD-Indikator ein Multi-Line-Indikator ist, werden drei Datensätze berechnet.
[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)
Wir können das MACD-Chart mit dem obigen Code leicht zeichnen. Nicht nur die eingebauten Funktionen können mehrere Variablen zurückgeben, sondern auch die geschriebenen benutzerdefinierten Funktionen können mehrere Daten zurückgeben.
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)
Die Schreibmethode zur Verwendung von if und anderen Strukturen als Multiple Variable-Zuteilungen ähnelt ebenfalls der obigen benutzerdefinierten Funktion, und Sie können sie ausprobieren, wenn Sie interessiert sind.
[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)
Einige Funktionen können nicht im lokalen Code-Block des bedingten Zweigs geschrieben werden, hauptsächlich die folgenden Funktionen:
Barfarbe (), Füllfarbe (), Linie (), Indikator (), Grafik (), Grafikleuchten (), Grafikbild (), Grafikbild (), Grafikbild ().
Trading View wird mit Fehlern kompiliert, FMZ ist nicht so restriktiv, aber es wird empfohlen, die Spezifikationen von Trading View zu befolgen.
strategy("test", overlay=true)
if close > open
plot(close, title="close")
else
plot(open, title="open")
Beispiel für Erläuterungen:
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)
Schlüsselpunkt: Ausdrücke, die für Beurteilungen verwendet werden, die Boolean-Werte zurückgeben. Beachten Sie die Einzug. Es kann höchstens noch eine Zweigstelle geben. Wenn alle Zweigstellen nicht wahr sind und es keine andere Zweigstelle gibt, geben Sie na zurück.
x = if close > open
close
plot(x, title="x")
Die Switch-Anweisung ist auch eine verzweigte strukturierte Anweisung, die verwendet wird, um verschiedene Pfade zu entwerfen, die unter bestimmten Bedingungen ausgeführt werden sollen.
Es gibt zwei Arten von Schalter, schauen wir uns die Beispiele einzeln an, um ihre Verwendung zu verstehen.
switch
mit Ausdrücken - Beispiel Erklärung:// input.string: defval, title, options, tooltip
func = input.string("EMA", title="indicator name", tooltip="select the name of the indicator function to be used", options=["EMA", "SMA", "RMA", "WMA"])
// input.int: defval, title, options, tooltip
// param1 = input.int(10, title="period parameter")
fastPeriod = input.int(10, title="fastPeriod parameter", options=[5, 10, 20])
slowPeriod = input.int(20, title="slowPeriod parameter", options=[20, 25, 30])
data = input(close, title="data", tooltip="select the closing price, opening price, highest price...")
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)
Wir haben die Eingabefunktion schon früher gelernt, hier lernen wir zwei Funktionen weiter, die der Eingabe ähneln:input.string
, input.int
functions.
input.string
wird verwendet, um eine Zeichenfolge zurückzugeben, und dieinput.int
Funktion verwendet wird, um einen ganzen Wert zurückzugeben.options
Dieoptions
Parameter kann ein Array von optionalen Werten übergeben werden, wieoptions=["EMA", "SMA", "RMA", "WMA"]
undoptions=[5, 10, 20]
In diesem Fall müssen die Steuerelemente der Strategieoberfläche keine spezifischen Werte eingeben, sondern werden zu Dropdown-Boxen, um diese Optionen auszuwählen, die im Optionsparameter angegeben sind.
Der Wert der Variablen func ist eine Zeichenkette, und die Variable func wird als Ausdruck für switch verwendet (der eine Variable, Funktionsaufruf oder Ausdruck sein kann), um zu bestimmen, welcher Zweig im Switch ausgeführt wird.runtime.error("error")
Funktion ausgeführt wird, wodurch die Strategie eine Ausnahme wirft und stoppt.
In unserem obigen Testcode haben wir nach der letzten Zeile von runtime.error im standardmäßigen Branchcode-Block von switch keinen Code wie [na, na] hinzugefügt, um mit dem Rückgabewert kompatibel zu sein. Dieses Problem muss in der Trading View berücksichtigt werden. Wenn der Typ inkonsistent ist, wird ein Fehler gemeldet. Aber in FMZ, da der Typ nicht streng erforderlich ist, kann dieser Kompatibilitätscode weggelassen werden. Daher ist es nicht notwendig, die Typkompatibilität des Rückgabewerts von if und Switch Branches in FMZ zu berücksichtigen.
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)
Auf FMZ wird kein Fehler gemeldet, aber auf der Handelsansicht wird ein Fehler gemeldet, da der vom if-Zweig zurückgegebene Typ inkonsistent ist.
switch
ohne AusdruckAls nächstes schauen wir uns eine andere Möglichkeit an,switch
Das heißt, ohne Ausdrücke.
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)
Wie wir aus dem Testcode-Beispiel sehen können, wird der Switch mit der Ausführung des lokalen Codeblocks übereinstimmen, der auf der Branch-Bedingung wahr ist. Im Allgemeinen müssen sich die Branch-Bedingungen nach einer Switch-Anweisung gegenseitig ausschließen. Das heißt, oben und unten im Beispiel können nicht gleichzeitig wahr sein. Da der Switch nur den lokalen Codeblock eines Branches ausführen kann, können Sie, wenn Sie interessiert sind, diese Zeile im Code ersetzen:up = close > open // up = close < open
Sie werden feststellen, dass der Switch-Branch nur den ersten Branch ausführen kann. Darüber hinaus ist es notwendig, darauf zu achten, keine Funktionsanrufe in den Branch des Switches so weit wie möglich zu schreiben, da die Funktion nicht auf jeder BAR aufgerufen werden kann, was einige Datenberechnungsprobleme verursachen kann (es sei denn, wie im Beispiel "switch
mit den Ausdrücken "der Ausführungszweig ist deterministisch und wird während des Strategiebetriebs nicht geändert).
return value = for count = start count to final count by step length
statement // Note: There can be break and continue in the statement
statement // Note: The last statement is the return value
Die for-Anweisung ist sehr einfach zu bedienen, die for-Schleife kann schließlich einen Wert (oder mehrere Werte in Form von [a, b, c]) zurückgeben. Wie die Variable, die der Position
Diebreak
Schlüsselwort in der For-Schleife verwendet: die Schleife stoppt, wenn diebreak
Anweisung ausgeführt.
Diecontinue
Schlüsselwort in der For-Schleife verwendet:continue
Wenn die Anweisung ausgeführt wird, ignoriert die Schleife den Code nachcontinue
Die For-Anweisung gibt den Rückgabewert der letzten Ausführung der Schleife zurück und gibt null zurück, wenn kein Code ausgeführt wird.
Dann demonstrieren wir mit einem einfachen Beispiel:
ret = for i = 0 to 10 // We can increase the keyword by to modify the step length, FMZ does not support reverse loops such as i = 10 to 0 for now
// We can add condition settings, use continue to skip, use break to jump out
runtime.log("i:", i)
i // If this line is not written, it will return null because there is no variable to return
runtime.log("ret:", ret)
runtime.error("stop")
Diefor ... in
Die Aussage hat zwei Formen, die wir im folgenden Pseudocode illustrieren.
return value = for array element in array
statement // Note: There can be break and continue in the statement
statement // Note: The last statement is the return value
Return value = for [index variable, array element corresponding to index variable] in array
statement // Note: There can be break and continue in the statement
statement // Note: The last statement is the return value
Wir können sehen, dass der Hauptunterschied zwischen den beiden Formen der Inhalt ist, der dem Schlüsselwort for folgt, einer ist die Verwendung einer Variable als Variable, die sich auf die Elemente des Arrays bezieht, der andere ist die Verwendung einer Struktur, die Indexvariablen, Tupel von Array-Elementvariablen als Referenzen enthält.
testArray = array.from(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
for ele in testArray // Modify it to the form of [i, ele]: for [i, ele] in testArray, runtime.log("ele:", ele, ", i:", i)
runtime.log("ele:", ele)
runtime.error("stop")
Wenn Sie den Index verwenden müssen, verwenden Sie die Grammatikfor [i, ele] in testArray
.
Anwendungsbereich der für Schleifen
Wir können die in der Pine-Sprache bereitgestellten eingebauten Funktionen verwenden, um einige der Loop-Logikberechnungen abzuschließen, die entweder direkt mit der Loop-Struktur geschrieben oder mit den eingebauten Funktionen verarbeitet werden.
Bei der Konstruktion mit einer Schleifstruktur:
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)
Das Beispiel verwendet eine For-Schleife, um die Summe zu berechnen und dann den Mittelwert zu berechnen.
Berechnen Sie den gleitenden Durchschnitt direkt mit der eingebauten Funktion:
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Verwenden Sie die eingebaute Funktionta.sma
Es ist offensichtlich einfacher, die eingebaute Funktion zur Berechnung des gleitenden Durchschnitts zu verwenden.
Wir verwenden immer noch das obige Beispiel zum Veranschaulichen.
Bei der Konstruktion mit einer Schleifstruktur:
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)
Für die Berechnung der Summe aller Elemente in einem Array können wir eine Schleife verwenden, um es zu verarbeiten, oder verwenden Sie die eingebaute Funktionarray.sum
Ich habe eine Frage an Sie.
Berechnen Sie die Summe direkt mit der eingebauten Funktion:
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)
Wir können sehen, dass die berechneten Daten genau die gleichen sind wie die, die auf der Grafik mit Grafiken angezeigt werden.
Warum also Schleifen entwerfen, wenn wir all das mit eingebauten Funktionen tun können?
Diewhile
Die Anweisung hält den Code in der Schleife auszuführen, bis die Beurteilungsbedingung in der while-Struktur falsch ist.
return value = while judgment condition
statement // Note: There can be break and continue in the statement
statement // Note: The last statement is the return value
Andere Regeln von while ähneln denen der for-Schleife. Die letzte Zeile des lokalen Code-Blocks des Loop-Körpers ist der Rückgabewert, der mehrere Werte zurückgeben kann. Die Schleife wird ausgeführt, wenn die
Wir verwenden weiterhin das Beispiel der Berechnung gleitender Durchschnitte zur Demonstration:
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)
Wir können sehen, dass die while-Schleife auch sehr einfach zu bedienen ist, und es ist auch möglich, einige Berechnungslogik zu entwerfen, die nicht durch die eingebauten Funktionen ersetzt werden kann, wie die Berechnung von Faktoren:
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
Die Definition von Arrays in der Pine-Sprache ist ähnlich wie in anderen Programmiersprachen. Pine[]
Um auf ein Element im Array zu verweisen, müssen wir die Funktionen verwendenarray.get()
undarray.set()
Die Indexreihenfolge der Elemente im Array ist, dass der Index des ersten Elements des Arrays 0 beträgt und der Index des nächsten Elements um 1 erhöht wird.
Wir veranschaulichen es mit einem einfachen Code:
var a = array.from(0)
if bar_index == 0
runtime.log("current value a on BAR:", a, ", a on the last BAR, i.e. the value of a[1]:", a[1])
else if bar_index == 1
array.push(a, bar_index)
runtime.log("current value a on BAR:", a, ", a on the last BAR, i.e. the value of a[1]:", a[1])
else if bar_index == 2
array.push(a, bar_index)
runtime.log("current value a on BAR:", a, ", a on the last BAR, i.e. the value of a[1]:", a[1], ", a on the last second BAR, i.e. the value of a[2]:", a[2])
else if bar_index == 3
array.push(a, bar_index)
runtime.log("current value a on BAR:", a, ", a on the last BAR, i.e. the value of a[1]:", a[1], ", a on the last second BAR, i.e. the value of a[2]:", a[2], ", a on the last third BAR, i.e. the value of a[3]:", a[3])
else if bar_index == 4
// Obtain elements by index using array.get, modify elements by index using array.set
runtime.log("Before array modification:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))
array.set(a, 1, 999)
runtime.log("After array modification:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))
Verwendungarray<int> a
, float[] b
um ein Array zu deklarieren oder einfach eine Variable zu deklarieren, die einem Array zugewiesen werden kann, zum Beispiel:
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")
Die Array-Variablen werden mit derarray.new
undarray.from
Es gibt auch viele typenbezogene Funktionen ähnlich wiearray.newin der Kiefersprache:array.new_int()
, array.new_bool()
, array.new_color()
, array.new_string()
, usw.
Das Schlüsselwort var funktioniert auch mit dem Array-Deklarationsmodus. Arrays, die mit dem Schlüsselwort var deklariert werden, werden nur auf der ersten BAR initialisiert.
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")
Es kann gesehen werden, dass die Änderungen des Arrays a kontinuierlich bestimmt und nicht zurückgesetzt wurden. Das Array b wird auf jeder BAR initialisiert.barstate.islast
ist wahr, gibt es immer noch nur ein Element mit einem Wert von 0.
Verwenden Sie array.get, um das Element an der angegebenen Indexposition im Array zu erhalten, und verwenden Sie array.set, um das Element an der angegebenen Indexposition im Array zu ändern.
Der erste Parameter von array.get ist das zu verarbeitende Array, und der zweite Parameter ist der angegebene Index. Der erste Parameter von array.set ist das zu verarbeitende Array, der zweite Parameter ist der angegebene Index und der dritte Parameter ist das zu schreibende Element.
Wir verwenden das folgende einfache Beispiel:
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")
Das Beispiel initialisiert die Grundfarbe grün, deklariert und initialisiert ein Array, um Farben zu speichern, und weist dann den Farben unterschiedliche Transparenzwerte zu (mit Hilfe dercolor.newDer Farbwert wird berechnet, indem man den Abstand des aktuellen BARs vom maximalen Wert von HIGH in 100 Lookback-Perioden berechnet. Je näher der Abstand zum maximalen Wert von HIGH in den letzten 100 Lookback-Zyklen ist, desto höher ist der Rang und desto dunkler (niedriger Transparenz) der entsprechende Farbwert. Viele ähnliche Strategien verwenden diese Methode, um den aktuellen Preisniveau innerhalb von N Lookback-Perioden darzustellen.
Wie man durch ein Array iteriert, können wir die for/for in/while Anweisungen verwenden, die wir zuvor gelernt haben.
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")
Diese drei Durchlaufmethoden haben die gleichen Ausführungsergebnisse.
Arrays können im globalen Bereich eines Skripts oder im lokalen Bereich einer Funktion oder eines If-Branches deklariert werden.
Für die Verwendung von Elementen in Arrays sind die folgenden Möglichkeiten gleichwertig. Wir können durch das folgende Beispiel sehen, dass zwei Liniensätze auf dem Diagramm gezogen werden, zwei in jedem Satz, und die beiden Linien in jedem Satz haben genau den gleichen Wert.
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)
array.unshift()
, array.insert()
, array.push()
.
array.remove()
, array.shift()
, array.pop()
, array.clear()
.
Wir verwenden das folgende Beispiel, um diese Array-Zusatz- und Löschoperationsfunktionen zu testen.
a = array.from("A", "B", "C")
ret = array.unshift(a, "X")
runtime.log("array a:", a, ", ret:", ret)
ret := array.insert(a, 1, "Y")
runtime.log("array a:", a, ", ret:", ret)
ret := array.push(a, "D")
runtime.log("array a:", a, ", ret:", ret)
ret := array.remove(a, 2)
runtime.log("array a:", a, ", ret:", ret)
ret := array.shift(a)
runtime.log("array a:", a, ", ret:", ret)
ret := array.pop(a)
runtime.log("array a:", a, ", ret:", ret)
ret := array.clear(a)
runtime.log("array a:", a, ", ret:", ret)
runtime.error("stop")
Anwendung von Ergänzungen, Löschungen: Arrays als Warteschlangen
Wir können eine
Eine Warteschlange ist eine Struktur, die häufig im Bereich der Programmierung verwendet wird. Die Merkmale einer Warteschlange sind:
Das Element, das zuerst in die Warteschlange kommt, verlässt die Warteschlange zuerst.
Auf diese Weise wird sichergestellt, dass die Daten in der Warteschlange die neuesten Daten sind und dass sich die Warteschlange nicht unbegrenzt erweitert.
In dem folgenden Beispiel verwenden wir eine Warteschlange, um den Preis jedes Ticks aufzuzeichnen, den mobilen Durchschnittspreis auf dem Tickspiegel zu berechnen und ihn dann mit dem gleitenden Durchschnitt auf der 1-minütigen K-Line-Ebene zu vergleichen.
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")
Beachten Sie, dass wir beim Deklarieren von Array a den Deklarierungsmodus angeben und das Schlüsselwortvariant
Auf diese Weise wird jede Preisänderung in der Matrix a erfasst.
Berechnung der Korrelationsfunktionen:
array.avg()
berechnet den Durchschnittswert aller Elemente in einem Array,array.min()
berechnet das kleinste Element in einem Array,array.max()
berechnet das kleinste Element in einem Array,array.stdev()
berechnet die Standardabweichung aller Elemente in einem Array,array.sum()
berechnet die Standardabweichung aller Elemente in einem Array.
Betriebsbezogene Funktionen:array.concat()
Um zwei Arrays zu verschmelzen oder zu verketten.array.copy()
um das Array zu kopieren.array.join
to verknüpft alle Elemente eines Arrays in eine Zeichenfolge.array.sort()
nach Aufstiegs- oder Abstiegsreihenfolge sortieren.array.reverse()
Um die Anordnung umzukehren.array.slice()
um die Matrix zu schneiden.array.includes()
Das Element zu beurteilen.array.indexof()
Wenn der Wert nicht gefunden wird, wird -1 zurückgegeben.array.lastindexof()
um das letzte Auftreten des Wertes zu finden.
Prüfbeispiele für Arrayberechnungsfunktionen:
a = array.from(3, 2, 1, 4, 5, 6, 7, 8, 9)
runtime.log("Arithmetic average of the array a:", array.avg(a))
runtime.log("The minimum element in the array a:", array.min(a))
runtime.log("The maximum element in the array a:", array.max(a))
runtime.log("Standard deviation in array a:", array.stdev(a))
runtime.log("Sum of all elements of the array a:", array.sum(a))
runtime.error("stop")
Dies sind häufig verwendete Array-Rechenfunktionen.
Beispiele für betriebliche Funktionen:
a = array.from(1, 2, 3, 4, 5, 6)
b = array.from(11, 2, 13, 4, 15, 6)
runtime.log("array a: ", a, ", array b: ", b)
runtime.log("array a, array b is concatenated with:", array.concat(a, b))
c = array.copy(b)
runtime.log("Copy an array b and assign it to the variable c, variable c:", c)
runtime.log("use array.join to process the array c, add the symbol + to the middle of each element, concatenating all elements results in a string:", array.join(c, "+"))
runtime.log("Sort the array b, in order from smallest to largest, using the parameter order.ascending:", array.sort(b, order.ascending)) // array.sort function modifies the original array
runtime.log("Sort the array b, in order from largest to smallest, using the parameter order.descending:", array.sort(b, order.descending)) // array.sort function modifies the original array
runtime.log("array a:", a, ", array b:", b)
array.reverse(a) // This function modifies the original array
runtime.log("reverse the order of all elements in the array a, after reversing, the array a is:", a)
runtime.log("Intercept array a, index 0~index 3, and follow the rule of left-closed and right-open interval:", array.slice(a, 0, 3))
runtime.log("Search for element 11 in array b:", array.includes(b, 11))
runtime.log("Search for element 100 in array a:", array.includes(a, 100))
runtime.log("Connect array a and array b, and search the index position of the first occurrence of element 2:", array.indexof(array.concat(a, b), 2), " , observe array.concat(a, b):", array.concat(a, b))
runtime.log("Connect array a and array b, and search the index position of the last occurrence of element 6:", array.lastindexof(array.concat(a, b), 6), " , observe array.concat(a, b):", array.concat(a, b))
runtime.error("stop")
Die Pine-Sprache kann mit benutzerdefinierten Funktionen gestaltet werden.
barcolor(), fill(), hline(), plot(), plotbar(), plotcandle()
) kann nicht in benutzerdefinierten Funktionen aufgerufen werden.Wir haben die benutzerdefinierten Funktionen auch in unseren früheren Tutorials viele Male verwendet, wie zum Beispiel die, die als eine einzige Zeile entworfen wurden:
barIsUp() => close > open
Ob die aktuelle BAR eine positive Linie ist, wenn die Funktion zurückkehrt.
Benutzerdefinierte Funktionen, die für mehrere Zeilen ausgelegt sind:
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)
Wir verwenden eine benutzerdefinierte Funktion, um eine Funktion der SMA-Durchschnittsberechnung zu realisieren.
Darüber hinaus gibt es zwei Beispiele für benutzerdefinierte Funktionen, die wir zurückgeben können:
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)
Eine Funktion kann die schnelle Linie, die langsame Linie und zwei EMA-Durchschnitte berechnen.
Die integriertenFMZ PINE Skriptdokument.
Klassifizierung der eingebauten Funktionen in der Pine-Sprache:
str.
series.color.
series.input.
series.ta.
series.plot.
series.array.
series.strategy.
series.math.
series.request.
Serienfunktionen, Typbehandlungsfunktionen usw.)Diestrategy.
Funktionsreihen sind Funktionen, die wir häufig bei der Gestaltung von Strategien verwenden, und diese Funktionen sind eng mit der Ausführung von Handelsoperationen verbunden, wenn die Strategie speziell ausgeführt wird.
strategy.entry
strategy.entry
Funktion ist eine wichtigere Funktion, wenn wir eine Strategie schreiben, um eine Bestellung zu platzieren, sind mehrere wichtige Parameter für die Funktion:id
, direction
, qty
, when
, usw.
Parameter:
id
: Dies kann verstanden werden als die Angabe eines Namens für eine Handelsposition zur Referenz.direction
: Wenn die Bestellrichtung lang ist (kaufen), geben Sie die eingebaute Variable einstrategy.long
, und wenn Sie kurz gehen wollen (verkaufen), geben Sie die Variablestrategy.short
.qty
: Geben Sie den zu platzierenden Auftragsbetrag an, wenn dieser Parameter nicht übergeben wird, wird der Standardbetrag der Aufträge verwendet.when
: Ausführungsbedingung, Sie können diesen Parameter angeben, um zu kontrollieren, ob diese aktuelle Auftragsoperation ausgelöst wird oder nicht.limit
: Geben Sie den Auftragsbegrenzungspreis an.stop
Stop-Loss-Preis.Die spezifischen Einzelheiten der Ausführung desstrategy.entry
Funktion durch die Parameter-Einstellungen gesteuert werden, wenn diestrategy
Funktion aufgerufen wird, und es kann auch durch die gesteuert werden [
Wir konzentrieren unspyramiding
, default_qty_value
Parameter in derstrategy
Wir verwenden den folgenden Code zum Testen:
/*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)
Der Teil am Anfang des Codes/* backtest... */
ist eine Backtest-Einstellung, die verwendet wird, um die Backtest-Einstellungszeit und andere Informationen zu diesem Zeitpunkt für das Debugging zu erfassen, nicht den Startcode.
Der Code lautet:strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)
, wenn wir diepyramiding
Parameter als 3, setzen wir die maximale Anzahl der Trades in der gleichen Richtung auf 3. Also eine der vierstrategy.entry
Da wir auch angegeben haben, diedefault_qty_value
Parameter 0,1, dasstrategy.entry
Betrieb mit IDlong1
hat eine Standardordergröße von 0,1strategy.entry
Funktion aufrufen, wenn wir diedirection
alsstrategy.long
, also sind die Test-Backtest-Bestellungen alle Kaufbestellungen.
Beachten Sie, dass die Bestelloperationstrategy.entry("long3", ...
in dem Code zweimal für die gleiche ID aufgerufen wird:long3
, die erstestrategy.entry
Die zweite Aufforderung an diestrategy.entry
Eine andere Möglichkeit ist, wenn z. B. die erste Reihenfolge mit ID strategy.entry
Funktion, um Aufträge gemäß der ID
strategy.close
Diestrategy.close
Die Funktion wird verwendet, um die Eingangsposition mit der angegebenen Identifikationskennung zu schließen.id
, when
, qty
, qty_percent
.
Parameter:
id
: Die zu schließende Eintritts-ID ist die ID, die wir angeben, wenn wir eine Position mit einer Eintritts-Orderfunktion eröffnen, z. B.strategy.entry
.when
: Durchführungsbedingungen.qty
: Anzahl der geschlossenen Positionen.qty_percent
: Prozentsatz der geschlossenen PositionenLassen Sie uns mit einem Beispiel die Einzelheiten der Verwendung dieser Funktion kennenlernen:
Die/*backtest ... */
in dem Code sind die Konfigurationsinformationen fürFMZ.COMInternational Website Backtest, Sie können es löschen und setzen Sie den Markt, Sorte, Zeitrahmen und andere Informationen, die Sie testen müssen.
/*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") // Multiple entry orders, no qty parameters specified, close all
// strategy.close() // Without specifying the id parameter, the current position will be closed
// strategy.close("long2") // If a non-existent id is specified then nothing is done
// strategy.close("long1", qty=0.15) // Specify qty parameters to close a position
// strategy.close("long1", qty_percent=50) // qty_percent is set to 50 to close 50% of the positions marked by long1
// strategy.close("long1", qty_percent=80, when=close<open) // Specify the parameter when, change it to close>open and it won't trigger
enableStop := true
Die Teststrategie zeigt drei aufeinanderfolgende lange Eingaben mit der Eingabe-ID strategy.close
Die Funktion zur Einstellung der verschiedenen Ergebnisse des Backtests beim Schließen einer Position.strategy.close
Funktion hat keine Parameter, um den Preis der Bestellung zum Schließen der Position anzugeben, diese Funktion wird hauptsächlich verwendet, um die Position sofort zum aktuellen Marktpreis zu schließen.
strategy.close_all
Die Funktionstrategy.close_all
wird verwendet, um alle aktuellen Positionen zu schließen, weil die Pine-Skript-Sprache Positionen nur eine Richtung haben kann, das heißt, wenn es ein Signal in der entgegengesetzten Richtung der aktuellen Position ausgelöst wird die aktuelle Position schließen und dann öffnen Sie es nach dem Signal auslösen.strategy.close_all
Der Hauptparameter derstrategy.close_all
Funktion ist:when
.
Parameter:
when
: Durchführungsbedingungen.Lassen Sie uns ein Beispiel verwenden:
/*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
Der Prüfcode beginnt mit einer Positionsnummer 0 (d. h.strategy.position_size==0
ist wahr), so dass, wenn die Bedingungen, die durch die wenn Parameter erfüllt sind, nur diestrategy.entry
Eintrittsfunktion mit ID strategy.position_size
ist größer als 0, dann kann die Eingabefunktion mit ID strategy.position_size < 0
, d. h. wenn eine Short-Position gehalten wird, werden alle Positionen in der aktuellen Halterichtung geschlossen.enableStop := true
. Stoppt die Strategieausführung, damit das Protokoll beobachtet werden kann.
Es kann festgestellt werden, dass die Funktionstrategy.close_all
Die Funktion "Lösung der Position" ist eine Funktion, bei der der Bestellpreis nicht angegeben wird.
strategy.exit
Diestrategy.exit
Diese Funktion wird verwendet, um eine Eingangsposition zu schließen.strategy.close
undstrategy.close_all
Die Funktionen schließen eine Position sofort zum aktuellen Marktpreis ab.strategy.exit
Die Funktion schließt die Position nach den Parameter-Einstellungen.
Parameter:
id
: Die Auftragsidentifikator-ID der aktuellen Auftragsverbindung.from_entry
: Verwendet zur Angabe der Eingabe-ID der zu schließenden Position.qty
: Anzahl der geschlossenen Positionen.qty_percent
: Prozentsatz der geschlossenen Positionen, Bereich: 0 ~ 100.profit
: Gewinnziel in Punkten.loss
: Stop-Loss-Ziel, ausgedrückt in Punkten.limit
: Gewinnziel, durch Preis angegeben.stop
: Stop-Loss-Ziel, angegeben durch den Preis.when
: Durchführungsbedingungen.Verwenden Sie eine Teststrategie, um die Parameterverwendung zu verstehen.
/*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") // If only one id parameter is specified, the exit order is invalid, and the parameters profit, limit, loss, stop and other exit conditions also need to be set at least one, otherwise it is also invalid
strategy.exit("exit1", "long1", profit=50) // Since the long1 entry order is not filled, the exit order with ID exit1 is also on hold until the corresponding entry order is filled before exit1 is placed
strategy.exit("exit2", "long2", qty=0.1, profit=100) // Specify the parameter qty to close 0.1 positions in the position with ID long2
strategy.exit("exit3", "long3", qty_percent=50, limit=strategy.opentrades.entry_price(findOrderIdx("long3")) + 1000) // Specify the parameter qty_percent to close 50% of the positions in the position with ID long3
isExit := true
if bar_index == 0
runtime.log("The price per point:", syminfo.mintick) // The price per point is related to the "Pricing Currency Precision" parameter setting on the Pine language template parameters
Wir verwenden das Echtzeit-Preismodell für Backtest, die Teststrategie beginnt mit 3 Eingabeoperationen (strategy.entry
Funktion) undlong1
wird absichtlich mitlimit
Parameter mit einem ausstehenden Auftragspreis von 1, so dass es nicht ausgefüllt werden kann.strategy.exit
Wir haben die strategy.exit
Funktion hat auch komplexere Trailing Stop-Parameter:trail_price
, trail_points
, trail_offset
kann auch in diesem Beispiel getestet werden, um ihre Verwendung zu lernen.
strategy.cancel
Diestrategy.cancel
Funktionen werden verwendet, um alle ausstehenden Aufträge zu stornieren/stoppen.strategy.order
, strategy.entry
, strategy.exit
Die wichtigsten Parameter dieser Funktion sind:id
, when
.
Parameter:
id
: Die Eintrittskarte wird gestrichen.when
: Durchführungsbedingungen.Diese Funktion ist leicht zu verstehen und wird verwendet, um nicht ausgefüllte Eintrittsbestellungen zu stornieren.
/*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