Bài hướng dẫn giới thiệu về ngôn ngữ PINE của FMZ Quant

Tác giả:Lydia., Tạo: 2022-09-23 15:23:34, Cập nhật: 2024-02-27 16:47:41

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

Ưu tiên của nhà điều hành

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 +-nottrong 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.

Các biến số

Tuyên bố biến đổi

Chúng ta đã nghiên cứu khái niệm marker trước đây, nó được sử dụng như tên của một biến, nghĩa là một biến là một dấu hiệu giữ một giá trị.

  • Chế độ khai báo: Điều đầu tiên cần viết khi khai báo một biến là mốt khai báo. Có ba chế độ khai báo cho biến:

    1. Sử dụng từ khóavar.
    2. Sử dụng từ khóavarip.
    3. Không viết gì cả.

    Cácvarvariptừ 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ặcswitchvà 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.

img

Chúng tôi giới thiệu một số thông số chính của hàm đầu vào:

  • defval: Giá trị mặc định cho các tùy chọn tham số chiến lược được đặt bởi hàm đầu vào, hỗ trợ các biến tích hợp trong ngôn ngữ Pine, giá trị số và chuỗi.
  • Tiêu đề: Tên tham số của chiến lược được hiển thị trên giao diện chiến lược trong giao dịch trực tiếp / backtesting.
  • Tooltip: Thông tin về tooltip cho các tham số chiến lược, khi chuột di chuyển qua tham số chiến lược, thông tin văn bản của cài đặt tham số sẽ được hiển thị.
  • Nhóm: Tên của nhóm tham số chiến lược, có thể được sử dụng cho các tham số chiến lược.

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.macdchứ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)

Cấu trúc điều kiện

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

if tuyên bố

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

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.

  1. Tuyên bố chuyển đổi, giống như câu lệnh if, cũng có thể trả về một giá trị.
  2. Không giống như lệnh chuyển đổi trong các ngôn ngữ khác, khi cấu trúc chuyển đổi được thực thi, chỉ một khối cốt lõi của mã của nó được thực thi, vì vậy lệnh break là không cần thiết (tức là, không cần phải viết các từ khóa như break).
  3. Mỗi nhánh của chuyển đổi có thể viết một khối mã cục bộ, dòng cuối cùng của khối mã cục bộ này là giá trị trả về (nó có thể là một tuple của các giá trị). trả về na nếu không có khối mã cục bộ nào được thực thi.
  4. Các biểu thức trong cấu trúc chuyển đổi xác định vị trí có thể viết một chuỗi, biến, biểu thức hoặc gọi hàm.
  5. switch cho phép xác định một giá trị trả về hoạt động như giá trị mặc định được sử dụng khi không có trường hợp khác trong cấu trúc để thực hiện.

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.

  1. Aswitchvớ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.inttrong ví dụ, có một cách sử dụng mới củaoptionscác tham số.optionstham 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"]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.

  1. switchkhông có biểu thức

Tiế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 < openBạ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 "switchvớ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).

Cấu trúc vòng lặp

cho tuyên bố

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í return value trong mã giả trên. Câu lệnh for được theo sau bởi một biến count được sử dụng để kiểm soát số lượng vòng lặp, tham khảo các giá trị khác, v.v.

Cácbreaktừ khóa được sử dụng trong vòng lặp for: vòng lặp dừng lại khibreaktuyên bố được thực hiện. CáccontinueTừ khóa được sử dụng trong vòng lặp for: Khicontinuelệnh được thực thi, vòng lặp sẽ bỏ qua mã sau khicontinuevà 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")

cho... trong tuyên bố

Cácfor ... intuyê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.

  1. Tính toán giá trị trung bình

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.

  1. Tóm lại

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?

  1. Đối với một số hoạt động và tính toán cho mảng.
  2. Để xem lại lịch sử, ví dụ, để tìm ra bao nhiêu điểm cao trong quá khứ cao hơn điểm cao của BAR hiện tại.
  3. Khi Pine ngôn ngữ tích hợp chức năng không thể hoàn thành tính toán cho BARs quá khứ.

trong khi statemnet

Cácwhilecâ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 loop đúng, và dừng vòng lặp khi điều kiện sai. Các câu lệnh break và continue cũng có thể được sử dụng trong thân vòng lặp.

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

Mảng

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

Xác định một mảng

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.newarray.fromcũ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.islastlà đúng, vẫn chỉ có một phần tử được in với giá trị 0.

Đọc và ghi các phần tử trong một mảng

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.

Iterate thông qua các phần tử mảng

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.

Các tham chiếu dữ liệu lịch sử

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

Chức năng thêm và xóa mảng

  1. Các chức năng liên quan đến hoạt động cộng các mảng:

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

  1. Các chức năng liên quan đến hoạt động xóa mảng:

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 queue bằng cách sử dụng mảng và một số chức năng thêm và xóa mảng. Mảng có thể được sử dụng để tính toán trung bình động của giá tick. Ai đó có thể hỏi, Tại sao chúng ta nên xây dựng một cấu trúc queue? Chúng ta không sử dụng mảng để tính toán trung bình trước đây?

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óavariantBằng cách này, mỗi thay đổi giá sẽ được ghi lại trong mảng a.

Các chức năng tính toán và vận hành mảng thường được sử dụng

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

Chức năng

Chức năng tùy chỉnh

Ngôn ngữ Pine có thể được thiết kế với các hàm tùy chỉnh.

  1. Tất cả các hàm được định nghĩa trong phạm vi toàn cầu của kịch bản. Một hàm không thể được tuyên bố trong một hàm khác.
  2. Các hàm không được phép tự gọi trong mã của riêng chúng (tái diễn).
  3. Về nguyên tắc, tất cả các chức năng vẽ trong ngôn ngữ PINE (barcolor(), fill(), hline(), plot(), plotbar(), plotcandle()) không thể được gọi trong các hàm tùy chỉnh.
  4. Các hàm có thể được viết dưới dạng một dòng hoặc nhiều dòng. Giá trị trả về của câu lệnh cuối cùng là giá trị trả về của hàm hiện tại, có thể được trả về dưới dạng tuple.

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á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:

  1. Chức năng xử lý chuỗistr. series.
  2. Chức năng xử lý giá trị màucolor. series.
  3. Chức năng đầu vào tham sốinput. series.
  4. Chức năng tính toán chỉ sốta. series.
  5. Chức năng vẽplot. series.
  6. Chức năng xử lý mảngarray. series.
  7. Các chức năng liên quan đến giao dịch củastrategy. series.
  8. Các chức năng liên quan đến các hoạt động toánmath. series.
  9. Các chức năng khác (chế độ xử lý thời gian, các chức năng vẽ chuỗi phi đồ thị,request.chức năng hàng loạt, chức năng xử lý loại, v.v.)

Chức năng giao dịch

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ể.


  1. strategy.entry

strategy.entryhà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.
  • stopGiá dừng lỗ.

Các chi tiết cụ thể về việc thực hiệnstrategy.entrychức năng được điều khiển bởi các thiết lập tham số khistrategyhàm được gọi, và nó cũng có thể được kiểm soát bởi [Pine Language Trade-Class Library Template Arguments](https://www.fmz.com/bbs-topic/9293#template-- arguments-of-pine-language-trade-class-library) thiết lập điều khiển, Pine language trade-class library template arguments kiểm soát chi tiết hơn về giao dịch, bạn có thể kiểm tra tài liệu liên kết để biết chi tiết.

Chúng tôi tập trung vàopyramiding, default_qty_valuecác thông số trongstrategyChú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 địnhpyramidingChúng ta đặt số lượng giao dịch tối đa theo cùng một hướng là 3.strategy.entryVì chúng ta cũng đã chỉ định cácdefault_qty_valuetham số là 0.1, điều nàystrategy.entryhoạt động với IDlong1có kích thước lệnh mặc định là 0.1.strategy.entrygọi hàm khi chúng ta chỉ địnhdirectionnhư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.entrylệnh không được thực hiện, và cuộc gọi thứ hai đếnstrategy.entryMột trường hợp khác, ví dụ: nếu thứ tự đầu tiên với ID long3 được điền, tiếp tục sử dụngstrategy.entrychức năng để đặt lệnh theo ID long3, sau đó các vị trí lệnh sẽ được tích lũy trên ID long3.


  1. strategy.close

Cácstrategy.closechứ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 long1 và sau đó sử dụng các tham số khác nhau củastrategy.closechứ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.closechứ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.


  1. 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_allsẽ đóng tất cả các vị trí trong hướng hiện tại khi nó được gọi.strategy.close_allchứ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==0là đú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.entrychức năng nhập với ID long được thực hiện. Sau khi giữ một vị trí dài,strategy.position_sizelà lớn hơn 0, thì hàm nhập với ID short có thể được thực hiện, vì vị trí dài hiện tại được giữ, tín hiệu đảo ngược ngắn này tại thời điểm này sẽ dẫn đến việc đóng vị trí dài và sau đó mở vị trí ngắn theo hướng ngược lại.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_allkhô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.


  1. strategy.exit

Cácstrategy.exitKhông giống như chức năng này,strategy.closestrategy.close_allCá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.exitchứ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.entrychức năng), vàlong1được cố tình đặt vớilimittham 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.exitChúng tôi đã sử dụng lấy lợi nhuận theo điểm lấy lợi nhuận theo giá , đóng một số vị trí cố định, và các vị trí đóng theo tỷ lệ phần trăm.strategy.exitchứ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_offsetcũng có thể được thử nghiệm trong ví dụ này để tìm hiểu sử dụng của họ.


  1. strategy.cancel

Cácstrategy.cancelcá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.exitCá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

Thêm nữa