Vì vậy, chúng ta thấy rằng trong ba đường vẽ a, b, và c, đường b chậm hơn đường a một BAR, và đường c chậm hơn đường b một BAR.
Chúng ta có thể kéo biểu đồ sang bên trái và quan sát thấy rằng trên đường K đầu tiên, cả giá trị của b và c đều là null (na). Điều này là do khi kịch bản được thực thi trên đường K đầu tiên BAR, nó không tồn tại khi tham chiếu đến giá trị lịch sử của một hoặc hai giai đoạn phía trước, mà không tồn tại. Do đó, chúng ta cần cẩn thận khi viết các chiến lược để kiểm tra xem tham chiếu dữ liệu lịch sử sẽ dẫn đến giá trị null hay không. Nếu giá trị null được sử dụng một cách không cẩn thận, nó sẽ gây ra một loạt các sự khác biệt tính toán, và thậm chí có thể ảnh hưởng đến BAR thời gian thực. Thông thường chúng ta sẽ sử dụng các hàm tích hợpna
, nz
để đánh giá trong mã (trên thực tế, chúng tôi cũng đã gặp phảinz
, ```na`` trong các video trước đây của chúng tôi, bạn có nhớ chương nào không?) đối phó với trường hợp của các giá trị không, ví dụ:
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
Đây là một cách để xử lý các tham chiếu có thể đến các giá trị không (na).
Chúng ta đã học được rất nhiều toán tử trong ngôn ngữ Pine. Các toán tử này tạo thành các biểu thức thông qua các kết hợp khác nhau với các toán tử. Vậy ưu tiên của các hoạt động này là gì khi đánh giá trong các biểu thức? Cũng giống như số học chúng ta học ở trường, phép nhân và phép chia được tính đầu tiên, tiếp theo là phép cộng và trừ. Điều tương tự cũng đúng với các biểu thức trong ngôn ngữ Pine.
Ưu tiên | Các nhà khai thác |
---|---|
9 | [] |
8 | + 、- vànot trong toán tử unary |
7 | * 、/ 、% |
6 | + 、- trong toán tử nhị phân |
5 | > 、< 、>= 、<= |
4 | == 、!= |
3 | and |
2 | or |
1 | ?: |
Các biểu thức ưu tiên cao được tính toán đầu tiên, và nếu các ưu tiên là như nhau, nó được đánh giá từ trái sang phải.()
để bọc biểu thức để buộc phần được đánh giá đầu tiên.
Chúng ta đã nghiên cứu khái niệm
Chế độ khai báo:
Điều đầu tiên cần viết khi khai báo một biến là
var
.varip
.Cácvar
vàvarip
từ khóa đã thực sự được nghiên cứu trong chương trước của chúng tôi trênAssignment Operators
, vì vậy chúng ta sẽ không đi vào chi tiết ở đây. Nếu không có gì được viết cho chế độ tuyên bố biến, như câu lệnh:i = 1
, như chúng tôi cũng đã đề cập trước đây, một biến được khai báo và gán như vậy được thực hiện trên mỗi K-line BAR.
Loại Ngôn ngữ Pine trên FMZ không nghiêm ngặt về các loại, và nó thường có thể bị bỏ qua. Tuy nhiên, để tương thích với chiến lược kịch bản trên Trading View, các biến cũng có thể được tuyên bố với các loại. Ví dụ:
int i = 0
float f = 1.1
Các yêu cầu về kiểu trên Trading View khá nghiêm ngặt và sẽ báo cáo lỗi nếu sử dụng mã sau trên Trading View:
baseLine0 = na // compile time error!
Đánh dấu Các dấu hiệu là tên biến. Việc đặt tên cho các dấu hiệu đã được đề cập trong các chương trước, vì vậy bạn có thể xem lại nó ở đây:https://www.fmz.com/bbs-topic/9637#markers
Tóm lại, tuyên bố một biến có thể được viết như sau:
// [<declaration_mode>] [<type>] <marker> = value
declaration mode type marker = value
Các toán tử phân bổ được sử dụng ở đây:=
gán giá trị cho một biến khi nó được khai báo. Khi gán giá trị có thể là một chuỗi, số, biểu thức, gọi hàm,if
, for
, while
, hoặcswitch
và các cấu trúc khác (những từ khóa cấu trúc và việc sử dụng tuyên bố này sẽ được giải thích chi tiết trong các khóa học tiếp theo.
Ở đây chúng ta tập trung vào chức năng đầu vào, đó là một chức năng mà chúng ta sẽ sử dụng thường xuyên khi thiết kế và viết chiến lược.
Chức năng đầu vào:
input function, parameters: defval、title、tooltip、inline、group
Chức năng đầu vào trên FMZ hơi khác với trên Trading View, nhưng chức năng này được sử dụng như đầu vào phân bổ các tham số chiến lược.
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)
Chức năng đầu vào thường được sử dụng để gán giá trị cho các biến khi tuyên bố chúng. Chức năng đầu vào trên FMZ vẽ các điều khiển để đặt các tham số chiến lược tự động trong giao diện chiến lược FMZ. Các điều khiển được hỗ trợ trên FMZ hiện bao gồm các hộp đầu vào số, hộp đầu vào văn bản, hộp thả xuống và hộp kiểm Boolean. Và bạn có thể đặt nhóm tham số chiến lược, đặt thông điệp văn bản nhắc tham số và các chức năng khác.
Chúng tôi giới thiệu một số thông số chính của hàm đầu vào:
Ngoài việc tuyên bố và gán biến số riêng lẻ, còn có một cách để tuyên bố một nhóm biến số và gán chúng trong ngôn ngữ Pine:
[Variable A, Variable B, Variable C] = function or structure, such as ```if```, ```for```, ```while``` or ```switch```
Thường gặp nhất là khi chúng ta sử dụngta.macd
chức năng để tính toán chỉ số MACD, vì chỉ số MACD là một chỉ số nhiều dòng, ba bộ dữ liệu được tính toán.
[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)
Chúng ta có thể vẽ biểu đồ MACD bằng cách sử dụng mã trên một cách dễ dàng. Không chỉ các hàm tích hợp có thể trả về nhiều biến, mà còn các hàm tùy chỉnh được viết có thể trả về nhiều dữ liệu.
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)
Phương pháp viết sử dụng if và các cấu trúc khác như việc gán nhiều biến cũng tương tự như hàm tùy chỉnh ở trên, và bạn có thể thử nếu bạn quan tâm.
[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)
Một số hàm không thể được viết trong khối mã địa phương của nhánh có điều kiện, chủ yếu bao gồm các hàm sau:
barcolor ((), fill ((), hline ((), indicator ((), plot ((), plotcandle ((), plotchar ((), plotshape (())
Trading View sẽ biên dịch với lỗi, FMZ không hạn chế như vậy, nhưng nên làm theo các thông số kỹ thuật của Trading View.
strategy("test", overlay=true)
if close > open
plot(close, title="close")
else
plot(open, title="open")
Ví dụ giải thích:
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)
Điểm quan trọng: Các biểu thức được sử dụng cho các phán quyết trả về các giá trị Boolean. Lưu ý dấu nhấp. Có thể có tối đa một nhánh khác. Nếu tất cả các biểu thức nhánh không đúng và không có nhánh khác, trả về na.
x = if close > open
close
plot(x, title="x")
Tuyên bố chuyển đổi cũng là một câu lệnh cấu trúc chi nhánh, được sử dụng để thiết kế các đường dẫn khác nhau để được thực hiện theo các điều kiện nhất định.
Có hai hình thức chuyển đổi, hãy xem các ví dụ từng ví dụ để hiểu cách sử dụng của chúng.
switch
với biểu thức - ví dụ giải thích:// 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)
Chúng ta đã học hàm đầu vào trước đây, ở đây chúng ta tiếp tục học hai hàm tương tự như đầu vào:input.string
, input.int
functions.
input.string
được sử dụng để trả về một chuỗi, vàinput.int
trong ví dụ, có một cách sử dụng mới củaoptions
các tham số.options
tham số có thể được vượt qua một mảng các giá trị tùy chọn, chẳng hạn nhưoptions=["EMA", "SMA", "RMA", "WMA"]
vàoptions=[5, 10, 20]
trong ví dụ (lưu ý rằng một loại là chuỗi, loại khác là số). Bằng cách này, các điều khiển trên giao diện chiến lược không cần phải nhập các giá trị cụ thể, nhưng các điều khiển trở thành hộp thả xuống để chọn các tùy chọn được cung cấp trong tham số tùy chọn.
Giá trị của biến func là một chuỗi, và biến func được sử dụng làm biểu thức cho switch (có thể là một biến, gọi hàm hoặc biểu thức) để xác định nhánh nào trong chuyển đổi được thực thi. Nếu biến func không thể khớp (tức là bằng) biểu thức trên bất kỳ nhánh nào trong chuyển đổi, khối mã nhánh mặc định sẽ được thực thi vàruntime.error("error")
chức năng sẽ được thực hiện, làm cho chiến lược để ném một ngoại lệ và dừng lại.
Trong mã thử nghiệm trên, sau dòng cuối cùng của runtime.error trong khối mã nhánh mặc định của chuyển đổi, chúng tôi không thêm mã như [na, na] để tương thích với giá trị trả về. Vấn đề này cần phải được xem xét trên Trading View. Nếu kiểu không phù hợp, sẽ báo cáo lỗi. Nhưng trên FMZ, vì kiểu không bắt buộc nghiêm ngặt, mã tương thích này có thể bị bỏ qua. Do đó, không cần phải xem xét tính tương thích kiểu của giá trị trả về if và chuyển đổi nhánh trên FMZ.
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)
Không có lỗi sẽ được báo cáo trên FMZ, nhưng một lỗi sẽ được báo cáo trên giao dịch xem. Bởi vì các loại trả về bởi if nhánh là không nhất quán.
switch
không có biểu thứcTiếp theo, hãy xem xét một cách khác để sử dụngswitch
, nghĩa là, không có biểu hiện.
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)
Như chúng ta có thể thấy từ ví dụ mã thử nghiệm, switch sẽ phù hợp với việc thực thi khối mã địa phương đúng trên điều kiện branch. Nói chung, các điều kiện branch sau lệnh switch phải độc lập lẫn nhau. nghĩa là, lên và xuống trong ví dụ không thể thực hiện cùng một lúc. Vì switch chỉ có thể thực thi khối mã địa phương của một nhánh, nếu bạn quan tâm, bạn có thể thay thế dòng này trong mã:up = close > open // up = close < open
Bạn sẽ thấy rằng switch branch chỉ có thể thực thi branch đầu tiên. Ngoài ra, cần phải chú ý không viết các cuộc gọi hàm trong branch của switch càng nhiều càng tốt, hàm không thể được gọi trên mỗi BAR có thể gây ra một số vấn đề tính toán dữ liệu (trừ khi trong ví dụ của "switch
với các biểu thức", nhánh thực thi là xác định và sẽ không được thay đổi trong quá trình hoạt động chiến lược).
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
Câu lệnh for rất đơn giản để sử dụng, vòng lặp for cuối cùng có thể trả về một giá trị (hoặc nhiều giá trị, dưới dạng [a, b, c]). Giống như biến được gán cho vị trí
Cácbreak
từ khóa được sử dụng trong vòng lặp for: vòng lặp dừng lại khibreak
tuyên bố được thực hiện.
Cáccontinue
Từ khóa được sử dụng trong vòng lặp for: Khicontinue
lệnh được thực thi, vòng lặp sẽ bỏ qua mã sau khicontinue
và thực thi vòng tiếp theo của vòng lặp trực tiếp. câu lệnh for trả về giá trị trả về từ lần thực hiện cuối cùng của vòng lặp. và nó trả về null nếu không có mã được thực thi.
Sau đó chúng ta sẽ chứng minh bằng một ví dụ đơn giản:
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")
Cácfor ... in
tuyên bố có hai hình thức, chúng tôi sẽ minh họa chúng trong mã giả sau.
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
Chúng ta có thể thấy rằng sự khác biệt chính giữa hai hình thức là nội dung sau từ khóa for, một là sử dụng một biến như một biến đề cập đến các yếu tố của mảng, một khác là sử dụng một cấu trúc chứa các biến chỉ mục, tuples của các biến yếu tố mảng như tham chiếu. Đối với các quy tắc giá trị trả về khác, chẳng hạn như sử dụng break, continue, vv, phù hợp với for loop. Chúng tôi cũng minh họa việc sử dụng bằng một ví dụ đơn giản.
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")
Khi nó cần sử dụng chỉ mục, sử dụng ngữ phápfor [i, ele] in testArray
.
Ứng dụng cho vòng lặp
Chúng ta có thể sử dụng các hàm tích hợp được cung cấp trong ngôn ngữ Pine để hoàn thành một số tính toán logic vòng lặp, được viết bằng cách sử dụng cấu trúc vòng lặp trực tiếp hoặc xử lý bằng các hàm tích hợp.
Khi thiết kế với cấu trúc vòng lặp:
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)
Ví dụ sử dụng vòng lặp for để tính tổng và sau đó tính giá trị trung bình.
Tính toán trung bình động trực tiếp bằng cách sử dụng hàm tích hợp:
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Sử dụng chức năng tích hợpta.sma
Đương nhiên, nó đơn giản hơn để sử dụng các chức năng tích hợp để tính toán trung bình di chuyển. bằng cách so sánh trên biểu đồ, bạn có thể thấy rằng kết quả tính toán là chính xác như nhau.
Chúng tôi vẫn sử dụng ví dụ trên để minh họa.
Khi thiết kế với cấu trúc vòng lặp:
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)
Để tính toán tổng của tất cả các phần tử trong một mảng, chúng ta có thể sử dụng một vòng lặp để xử lý nó, hoặc sử dụng chức năng tích hợparray.sum
để tính toán.
Tính toán tổng trực tiếp bằng cách sử dụng hàm tích hợp:
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)
Chúng ta có thể thấy dữ liệu được tính toán là chính xác giống như hiển thị trên biểu đồ sử dụng đồ thị.
Vì vậy, tại sao thiết kế vòng lặp khi chúng ta có thể làm tất cả những điều này với các chức năng tích hợp?
Cácwhile
câu lệnh giữ mã trong phần vòng lặp được thực hiện cho đến khi điều kiện phán quyết trong cấu trúc while là sai.
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
Các quy tắc khác của while tương tự như các quy tắc của vòng lặp for. Dòng cuối cùng của khối mã cục bộ của thân vòng lặp là giá trị trả về, có thể trả về nhiều giá trị. Thực hiện vòng lặp khi điều kiện
Chúng ta vẫn sẽ sử dụng ví dụ tính toán trung bình động để chứng minh:
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)
Chúng ta có thể thấy rằng vòng lặp while cũng rất đơn giản để sử dụng, và cũng có thể thiết kế một số logic tính toán mà không thể được thay thế bởi các hàm tích hợp, chẳng hạn như tính toán nhân:
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
Định nghĩa của mảng trong ngôn ngữ Pine tương tự như trong các ngôn ngữ lập trình khác. Mảng Pine là mảng một chiều. Thông thường nó được sử dụng để lưu trữ một chuỗi dữ liệu liên tục. Dữ liệu duy nhất được lưu trữ trong mảng được gọi là yếu tố của mảng, và các loại của các yếu tố này có thể là: số nguyên, dấu phẩy nổi, chuỗi, giá trị màu, giá trị boolean. Ngôn ngữ Pine trên FMZ không quá nghiêm ngặt về các loại, và thậm chí có thể lưu trữ các chuỗi và số trong mảng cùng một lúc.[]
để tham chiếu đến một phần tử trong mảng, chúng ta cần sử dụng các hàmarray.get()
vàarray.set()
. Trật tự chỉ số của các phần tử trong mảng là chỉ số của phần tử đầu tiên của mảng là 0, và chỉ số của phần tử tiếp theo được gia tăng bằng 1.
Chúng tôi minh họa nó bằng một mã đơn giản:
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))
Sử dụngarray<int> a
, float[] b
để tuyên bố một mảng hoặc chỉ tuyên bố một biến có thể được gán một mảng, ví dụ:
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")
Các biến mảng được khởi tạo bằng cách sử dụngarray.new
vàarray.from
cũng có rất nhiều loại liên quan đến các chức năng tương tự nhưarray.newbằng ngôn ngữ Pine:array.new_int()
, array.new_bool()
, array.new_color()
, array.new_string()
, vv
Từ khóa var cũng hoạt động với chế độ tuyên bố mảng. Mảng được tuyên bố bằng từ khóa var chỉ được khởi tạo trên BAR đầu tiên. Hãy quan sát bằng một ví dụ:
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")
Có thể thấy rằng các thay đổi của mảng a đã được xác định liên tục và không được đặt lại. mảng b được khởi tạo trên mỗi BAR. Cuối cùng, khibarstate.islast
là đúng, vẫn chỉ có một phần tử được in với giá trị 0.
Sử dụng array.get để lấy phần tử ở vị trí chỉ mục được chỉ định trong mảng, và sử dụng array.set để sửa đổi phần tử ở vị trí chỉ mục được chỉ định trong mảng.
Các tham số đầu tiên của array.get là mảng để được xử lý, và các tham số thứ hai là chỉ mục được chỉ định. Các tham số đầu tiên để array.set là mảng được xử lý, các tham số thứ hai là chỉ mục được chỉ định, và các tham số thứ ba là các phần tử được viết.
Chúng tôi sử dụng ví dụ đơn giản sau đây để minh họa:
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")
Ví dụ khởi tạo màu xanh lá cây cơ sở, tuyên bố và khởi tạo một mảng để lưu trữ màu sắc, và sau đó gán các giá trị độ minh bạch khác nhau cho các màu sắc (bằng cách sử dụngcolor.newCác chiến lược tương tự sử dụng phương pháp này để đại diện cho mức giá hiện tại trong N khoảng thời gian nhìn lại.
Làm thế nào để lặp lại thông qua một mảng, chúng ta có thể sử dụng cho / cho trong / trong khi tuyên bố mà chúng ta đã học trước đây.
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")
Ba phương pháp đi qua này có kết quả thực hiện giống nhau.
Các mảng có thể được tuyên bố trong phạm vi toàn cầu của một kịch bản, hoặc trong phạm vi cục bộ của một hàm hoặc if branch.
Đối với việc sử dụng các phần tử trong mảng, các cách sau đây là tương đương. Chúng ta có thể thấy bằng ví dụ sau đây rằng hai tập các đường được vẽ trên biểu đồ, hai trong mỗi tập, và hai đường trong mỗi tập có cùng giá trị.
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()
.
Chúng tôi sử dụng ví dụ sau đây để kiểm tra các hàm hoạt động thêm và xóa mảng này.
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")
Ứng dụng thêm, xóa: mảng như hàng đợi
Chúng ta có thể xây dựng một cấu trúc dữ liệu
Một queue là một cấu trúc thường được sử dụng trong lĩnh vực lập trình, các đặc điểm của một queue là:
Các yếu tố đi vào hàng đợi đầu tiên, rời hàng đợi đầu tiên.
Bằng cách này, nó đảm bảo rằng dữ liệu trong hàng đợi là dữ liệu mới nhất, và chiều dài của hàng đợi sẽ không mở rộng vô thời hạn.
Trong ví dụ sau, chúng tôi sử dụng cấu trúc hàng đợi để ghi lại giá của mỗi dấu chấm, tính giá trung bình di động ở mức dấu chấm, và sau đó so sánh nó với giá trung bình động ở mức đường K 1 phút.
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")
Lưu ý rằng khi tuyên bố mảng a, chúng tôi chỉ định chế độ tuyên bố và sử dụng từ khóavariant
Bằng cách này, mỗi thay đổi giá sẽ được ghi lại trong mảng a.
Tính toán các hàm tương quan:
array.avg()
tính giá trị trung bình của tất cả các phần tử trong một mảng,array.min()
tính toán phần tử nhỏ nhất trong một mảng,array.max()
tính toán phần tử nhỏ nhất trong một mảng,array.stdev()
tính toán độ lệch chuẩn của tất cả các phần tử trong một mảng,array.sum()
tính lệch chuẩn của tất cả các phần tử trong một mảng.
Các chức năng liên quan đến hoạt động:array.concat()
để hợp nhất hoặc liên kết hai mảng.array.copy()
để sao chép mảng.array.join
to liên kết tất cả các phần tử của một mảng thành một chuỗi.array.sort()
để sắp xếp theo thứ tự tăng hoặc giảm.array.reverse()
để đảo ngược mảng.array.slice()
để cắt các mảng.array.includes()
để đánh giá yếu tố.array.indexof()
để trả về chỉ số lần xuất hiện đầu tiên của giá trị được truyền vào như một tham số. Nếu giá trị không được tìm thấy, -1 sẽ được trả về.array.lastindexof()
để tìm lần xuất hiện cuối cùng của giá trị.
Ví dụ thử nghiệm các hàm liên quan đến tính toán mảng:
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")
Đây là các hàm tính toán mảng thường được sử dụng.
Ví dụ về các chức năng liên quan đến hoạt động:
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")
Ngôn ngữ Pine có thể được thiết kế với các hàm tùy chỉnh.
barcolor(), fill(), hline(), plot(), plotbar(), plotcandle()
) không thể được gọi trong các hàm tùy chỉnh.Chúng tôi cũng đã sử dụng các chức năng tùy chỉnh nhiều lần trong các hướng dẫn trước đây của chúng tôi, chẳng hạn như những người được thiết kế như một dòng duy nhất:
barIsUp() => close > open
Có phải BAR hiện tại là một đường thẳng dương khi hàm trả về không.
Các chức năng tùy chỉnh được thiết kế để nhiều dòng:
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)
Chúng tôi sử dụng một hàm tùy chỉnh để thực hiện một hàm của tính toán trung bình sma.
Ngoài ra, hai ví dụ về các hàm tùy chỉnh mà chúng ta có thể trả về:
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)
Một hàm có thể tính toán đường nhanh, đường chậm và hai đường trung bình EMA.
Các chức năng tích hợp có thể dễ dàng được tìm thấy trongTài liệu kịch bản FMZ PINE.
Phân loại các chức năng tích hợp trong ngôn ngữ Pine:
str.
series.color.
series.input.
series.ta.
series.plot.
series.array.
series.strategy.
series.math.
series.request.
chức năng hàng loạt, chức năng xử lý loại, v.v.)Cácstrategy.
chuỗi các chức năng là các chức năng mà chúng ta thường sử dụng trong thiết kế các chiến lược, và các chức năng này có liên quan chặt chẽ đến việc thực hiện các hoạt động giao dịch khi chiến lược đang chạy cụ thể.
strategy.entry
strategy.entry
hàm là một hàm quan trọng hơn khi chúng ta viết một chiến lược để đặt một lệnh, một số thông số quan trọng cho hàm là:id
, direction
, qty
, when
, vv
Các thông số:
id
: Điều này có thể được hiểu như là cho một tên cho một vị trí giao dịch để tham chiếu.direction
: Nếu hướng lệnh dài (mua), truyền vào biến tích hợpstrategy.long
, và nếu bạn muốn đi ngắn (bán), đi trong biếnstrategy.short
.qty
: Xác định số lượng lệnh được đặt, nếu tham số này không được thông qua, số lượng lệnh mặc định sẽ được sử dụng.when
: Điều kiện thực thi, bạn có thể chỉ định tham số này để kiểm soát liệu hoạt động lệnh hiện tại này có được kích hoạt hay không.limit
: Xác định giá giới hạn lệnh.stop
Giá dừng lỗ.Các chi tiết cụ thể về việc thực hiệnstrategy.entry
chức năng được điều khiển bởi các thiết lập tham số khistrategy
hàm được gọi, và nó cũng có thể được kiểm soát bởi [
Chúng tôi tập trung vàopyramiding
, default_qty_value
các thông số trongstrategy
Chúng tôi sử dụng mã sau đây để kiểm tra:
/*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)
Phần ở đầu mã/* backtest... */
là một cài đặt backtest, được sử dụng để ghi lại thời gian cài đặt backtest và thông tin khác tại thời điểm đó để gỡ lỗi, không phải là mã khởi động.
Trong mã:strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)
, khi chúng ta xác địnhpyramiding
Chúng ta đặt số lượng giao dịch tối đa theo cùng một hướng là 3.strategy.entry
Vì chúng ta cũng đã chỉ định cácdefault_qty_value
tham số là 0.1, điều nàystrategy.entry
hoạt động với IDlong1
có kích thước lệnh mặc định là 0.1.strategy.entry
gọi hàm khi chúng ta chỉ địnhdirection
nhưstrategy.long
, vì vậy các lệnh thử nghiệm backtest đều là lệnh mua.
Lưu ý rằng các hoạt động lệnhstrategy.entry("long3", ...
trong mã được gọi hai lần, cho cùng một ID:long3
, lần đầu tiênstrategy.entry
lệnh không được thực hiện, và cuộc gọi thứ hai đếnstrategy.entry
Một trường hợp khác, ví dụ: nếu thứ tự đầu tiên với ID strategy.entry
chức năng để đặt lệnh theo ID
strategy.close
Cácstrategy.close
chức năng được sử dụng để đóng vị trí nhập khẩu với ID nhận dạng được chỉ định. Các thông số chính là:id
, when
, qty
, qty_percent
.
Các thông số:
id
: ID đầu vào cần phải được đóng là ID mà chúng tôi chỉ định khi chúng tôi mở một vị trí sử dụng một chức năng lệnh đầu vào, chẳng hạn nhưstrategy.entry
.when
: Các điều kiện thực thi.qty
: Số lượng các vị trí đóng.qty_percent
: Tỷ lệ phần trăm các vị trí đóng.Chúng ta hãy làm quen với chi tiết về việc sử dụng chức năng này thông qua một ví dụ:
Các/*backtest ... */
trong mã là thông tin cấu hình choFMZ.COMbacktest trang web quốc tế, bạn có thể xóa nó và thiết lập thị trường, giống, khoảng thời gian và các thông tin khác bạn cần để kiểm tra.
/*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
Chiến lược thử nghiệm cho thấy ba mục dài liên tiếp với ID mục strategy.close
chức năng để thiết lập các kết quả khác nhau của backtest khi đóng một vị trí.strategy.close
chức năng không có tham số để xác định giá của lệnh để đóng vị trí, chức năng này chủ yếu được sử dụng để đóng vị trí ngay lập tức ở giá thị trường hiện tại.
strategy.close_all
Chức năngstrategy.close_all
được sử dụng để đóng tất cả các vị trí hiện tại, bởi vì các vị trí văn bản ngôn ngữ Pine chỉ có thể có một hướng, đó là, nếu có một tín hiệu được kích hoạt theo hướng ngược lại của vị trí hiện tại sẽ đóng vị trí hiện tại và sau đó mở nó theo tín hiệu kích hoạt.strategy.close_all
sẽ đóng tất cả các vị trí trong hướng hiện tại khi nó được gọi.strategy.close_all
chức năng là:when
.
Các thông số:
when
: Các điều kiện thực thi.Hãy dùng một ví dụ để quan sát:
/*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
Mã thử bắt đầu với số vị trí 0 (tức làstrategy.position_size==0
là đúng), do đó, khi các điều kiện được thiết lập bởi các khi tham số được đáp ứng, chỉstrategy.entry
chức năng nhập với ID strategy.position_size
là lớn hơn 0, thì hàm nhập với ID strategy.position_size < 0
, tức là khi giữ một vị trí ngắn, tất cả các vị trí trong hướng giữ hiện tại sẽ được đóng.enableStop := true
. Ngừng thực thi chiến lược để ghi chép có thể được quan sát.
Nó có thể được tìm thấy rằng các chức năngstrategy.close_all
không có tham số để xác định giá đóng lệnh, chức năng này chủ yếu được sử dụng để đóng ngay lập tức vị trí ở giá thị trường hiện tại.
strategy.exit
Cácstrategy.exit
Không giống như chức năng này,strategy.close
vàstrategy.close_all
Các chức năng đóng một vị trí ngay lập tức tại giá thị trường hiện tại.strategy.exit
chức năng sẽ đóng vị trí theo cài đặt tham số.
Các thông số:
id
: ID nhận dạng lệnh của lệnh hoàn tất hiện tại.from_entry
: Được sử dụng để chỉ định ID đầu vào của vị trí được đóng.qty
: Số lượng các vị trí đóng.qty_percent
: Tỷ lệ phần trăm các vị trí đóng, phạm vi: 0 ~ 100.profit
: Mục tiêu lợi nhuận, được thể hiện bằng điểm.loss
: Mục tiêu dừng lỗ, được thể hiện bằng điểm.limit
: Mục tiêu lợi nhuận, được xác định theo giá.stop
: Mục tiêu dừng lỗ, được xác định theo giá.when
: Các điều kiện thực thi.Sử dụng một chiến lược thử nghiệm để hiểu việc sử dụng tham số.
/*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
Chúng tôi sử dụng mô hình giá thời gian thực cho backtest, chiến lược thử nghiệm bắt đầu với 3 hoạt động nhập (strategy.entry
chức năng), vàlong1
được cố tình đặt vớilimit
tham số với một giá lệnh đang chờ của 1, do đó, nó không thể được lấp đầy. sau đó kiểm tra hàm thoát có điều kiệnstrategy.exit
Chúng tôi đã sử dụng strategy.exit
chức năng cũng có các thông số dừng kéo phức tạp hơn:trail_price
, trail_points
, trail_offset
cũng có thể được thử nghiệm trong ví dụ này để tìm hiểu sử dụng của họ.
strategy.cancel
Cácstrategy.cancel
các chức năng được sử dụng để hủy bỏ / dừng tất cả các đơn đặt hàng đang chờ.strategy.order
, strategy.entry
, strategy.exit
Các thông số chính của chức năng này là:id
, when
.
Các thông số:
id
: ID nhập học sẽ bị hủy bỏ.when
: Các điều kiện thực thi.Chức năng này dễ hiểu, và nó được sử dụng để hủy các đơn đặt hàng không được thực hiện.
/*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