Hướng dẫn giới thiệu ngôn ngữ PINE quantitative của Inventor
Video hướng dẫn:
Khó khăn trong việc giao dịch theo khối lượng? sử dụng giao dịch xem ngôn ngữ Pine từ nhỏ đến quan trọng - người mới bắt đầu ngôn ngữ Pine
Nền tảng giao dịch định lượng của nhà phát minh hỗ trợ các chiến lược viết ngôn ngữ Pine, hỗ trợ phản hồi, vận hành thực tế các chiến lược ngôn ngữ Pine, tương thích với các phiên bản thấp hơn của ngôn ngữ Pine. Trên nền tảng giao dịch định lượng của nhà phát minh (FMZ.COM)Quảng trường Chiến lượcCó rất nhiều chiến lược và kịch bản của Pine đã được thu thập và di chuyển.
FMZ không chỉ hỗ trợ ngôn ngữ Pine, mà còn hỗ trợ chức năng vẽ mạnh mẽ của ngôn ngữ Pine. Các tính năng trên nền tảng FMZ, các công cụ thực tế phong phú, quản lý dễ dàng và hiệu quả, cũng tăng cường thêm tính thực tế của chiến lược và kịch bản của Pine. FMZ dựa trên khả năng tương thích với ngôn ngữ Pine, đồng thời cũng đã mở rộng, tối ưu hóa và cắt xén ngôn ngữ Pine. Trước khi chính thức vào hướng dẫn, chúng ta hãy cùng nhau xem những thay đổi nào trong ngôn ngữ Pine trên FMZ và bản gốc của Pine.
Một số sự khác biệt rõ ràng:
-
1., Chính sách Pine trên FMZ, mã đầu tiên của phiên bản
//@versionVà mã bắt đầustrategy、indicatorKhông có yêu cầu bắt buộc để viết câu nói, FMZ tạm thời không hỗ trợimportNhập khẩulibrarychức năng.Một số chiến lược có thể được viết như sau:
pine//@version=5 indicator("My Script", overlay = true) src = close a = ta.sma(src, 5) b = ta.sma(src, 50) c = ta.cross(a, b) plot(a, color = color.blue) plot(b, color = color.black) plotshape(c, color = color.red)Hoặc là:
pine//@version=5 strategy("My Strategy", overlay=true) longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28)) if (longCondition) strategy.entry("My Long Entry Id", strategy.long) shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28)) if (shortCondition) strategy.entry("My Short Entry Id", strategy.short)Trong FMZ, nó có thể được rút gọn thành:
pinesrc = close a = ta.sma(src, 5) b = ta.sma(src, 50) c = ta.cross(a, b) plot(a, color = color.blue, overlay=true) plot(b, color = color.black, overlay=true) plotshape(c, color = color.red, overlay=true)Hoặc:
pinelongCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28)) if (longCondition) strategy.entry("My Long Entry Id", strategy.long) shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28)) if (shortCondition) strategy.entry("My Short Entry Id", strategy.short) -
2 , chiến lược ((script)) một số thiết lập liên quan đến giao dịch được thiết lập bởi tham số "Pine language transaction class library" trên giao diện chiến lược FMZ.
-
Mô hình giá đóng cửa so với mô hình giá thời gian thực
Trong giao dịch xem, chúng ta có thể đi quastrategyChức năngcalc_on_every_tickCác tham số để thiết lập kịch bản chiến lược thực hiện logic chiến lược trong thời gian thực mỗi khi giá thay đổi, tại thời điểm nàycalc_on_every_tickCác tham số nên được đặt làtrue◦ Tính mặc địnhcalc_on_every_tickCác tham số làfalseCác logic của chiến lược sẽ được thực hiện khi chiến lược hiện tại K BAR hoàn toàn đi qua.
Trên FMZ, bạn có thể cài đặt thông qua các tham số của mẫu "Pine language transaction class library". -
Kiểm soát chính xác các giá trị như giá cả, số lượng đặt hàng dưới khi thực hiện chiến lược cần được chỉ định trên FMZ
Trong giao dịch xem vì chỉ có thể thử nghiệm mô phỏng, do đó không có vấn đề về độ chính xác đặt hàng thời gian thực. Trên FMZ có thể chạy chiến lược pin trên thực. Sau đó, bạn cần chiến lược có thể linh hoạt chỉ định giá chính xác của loại giao dịch, số lượng đặt hàng chính xác. Những thiết lập chính xác này là kiểm soát số lượng nhỏ của dữ liệu liên quan, tránh dữ liệu không phù hợp với yêu cầu báo cáo của sàn giao dịch và do đó không thể đặt hàng. -
Mã hợp đồng tương lai
Các loại giao dịch trên FMZ nếu là hợp đồng, sẽ có 2 thuộc tính: "cặp giao dịch" và "mã hợp đồng". Ngoài việc cần thiết phải thiết lập các cặp giao dịch rõ ràng khi thực thi và phản hồi, bạn cũng cần thiết lập mã hợp đồng cụ thể trong tham số "mã hợp đồng" của mẫu "Pine Language Trading Library". Ví dụ như hợp đồng vĩnh viễn chỉ cần điền vàoswap, mã hợp đồng để xem cụ thể giao dịch hoạt động có hợp đồng này không. Ví dụ, có giao dịch tất cả các hợp đồng hàng quý, ở đây có thể được điềnquarterCác mã hợp đồng này tương ứng với mã hợp đồng tương lai được định nghĩa trong tài liệu Javascript/python/c++ của FMZ.
Các thiết lập khác như số lượng đơn hàng tối thiểu, số lượng đơn hàng mặc định, v.v. có thể được xem trong tài liệu ngôn ngữ Pine vềThư viện giao dịch ngôn ngữ PineThông tin về tham số.
-
-
3、
runtime.debug、runtime.log、runtime.errorFMZ là một hàm mở rộng được sử dụng để khởi động.3 chức năng được thêm vào nền tảng FMZ để khởi động.
-
runtime.debug: Chức năng này thường không được sử dụng để in thông tin biến trên bàn điều khiển. -
runtime.log: xuất nội dung trong nhật ký │ FMZ PINE có chức năng riêng │pineruntime.log(1, 2, 3, close, high, ...),可以传多个参数。 -
runtime.error: khi được gọi, sẽ gây ra lỗi chạy và có thông báo lỗi được chỉ định trong tham số message.pineruntime.error(message)
-
-
4, phần của hàm vẽ đã được mở rộng
overlaytham sốNgôn ngữ Pine trên FMZ, hàm vẽ
plot、plotshape、plotcharThêm nữa.overlayChức năng hỗ trợ cho phép chỉ định hình ảnh trên đồ họa chính hoặc đồ họa phụ.overlaycài đặttrueHình vẽ trên bản đồ chính, thiết lập làfalseHình vẽ trên phụ. Cho phép các chiến lược Pine trên FMZ có thể vẽ cả hình chính và hình phụ cùng một lúc. -
5、
syminfo.mintickLấy giá trị của biến tích hợpsyminfo.mintickBiến tích hợp được định nghĩa là giá trị đo tối thiểu của giống hiện tại. Trong FMZLời đề nghị chắc chắn/Kiểm tra ngượcCài đặt chính xác giá trị tiền tệ 2 nghĩa là giá trị giao dịch chính xác đến số nhỏ thứ hai, tại thời điểm đó giá trị thay đổi nhỏ nhất là 0.01syminfo.mintickGiá trị là 0.01 <unk>. -
6/ Giá trung bình trong FMZ PINE Script bao gồm phí xử lý
Ví dụ: giá đặt hàng là 8000, bán hướng, số lượng 1 tay (một tờ), giá trung bình sau khi giao dịch không phải là 8000, thấp hơn 8000 (chi phí bao gồm phí xử lý).
Khóa học ngôn ngữ Pine
Khi bắt đầu học nền tảng của ngôn ngữ Pine, có thể trong một số ví dụ, chúng ta không quen thuộc với các lệnh, ngữ pháp mã. Không hiểu thì không sao, chúng ta có thể quen thuộc với các khái niệm, hiểu mục đích của bài kiểm tra, hoặc có thể truy cập tài liệu ngôn ngữ Pine của FMZ để xem hướng dẫn. Sau đó, theo hướng dẫn từng bước một để dần dần quen thuộc với các ngữ pháp, lệnh, hàm, biến tích hợp.
Thực hiện mô hình
Khi bắt đầu học ngôn ngữ Pine, rất cần thiết để hiểu các khái niệm liên quan như quá trình thực hiện chương trình kịch bản ngôn ngữ Pine. Chiến lược ngôn ngữ Pine được vận hành dựa trên biểu đồ, có thể hiểu là chiến lược ngôn ngữ Pine là một loạt các tính toán và thao tác, được thực hiện trên biểu đồ theo thứ tự thời gian theo thứ tự thời gian, bắt đầu từ dữ liệu đầu tiên đã được tải lên biểu đồ.bar_indexDẫn đến giá trị chỉ mục của dòng K Bar hiện tại khi thực thi kịch bản Pine.
pine
plot(bar_index, "bar_index")
plotChức năng là một trong những chức năng chúng ta sẽ sử dụng nhiều hơn trong tương lai. Nó rất đơn giản để sử dụng, chỉ cần vẽ một đường trên biểu đồ dựa trên các tham số được truyền, và dữ liệu được truyền làbar_index, dòng tên làbar_index。 Bạn có thể thấy trên Bar đầu tiên, dòng có tên là bar_index có giá trị là 0, và tăng 1 。 khi Bar tăng về phía bên phải.
Các thiết lập khác nhau của chính sách và cách thức thực hiện mô hình chính sách khác nhau.收盘价模型Và实时价模型Các mô hình giá đóng cửa, mô hình giá thời gian thực đã được giới thiệu trước đây.
-
Mô hình giá đóng cửa
Khi mã chiến lược được thực hiện, chu kỳ của Bar K hiện tại được thực hiện hoàn toàn, khi K đóng thì chu kỳ K đã kết thúc. Tại thời điểm này, logic chiến lược Pine được thực hiện một lần nữa, và tín hiệu giao dịch được kích hoạt sẽ được thực hiện khi K Bar tiếp theo bắt đầu.
-
Mô hình giá thời gian thực
Khi mã chiến lược được thực hiện, Bar K hiện tại sẽ thực hiện logic chiến lược Pine một lần cho mỗi lần thay đổi, bất kể có đóng hay không, và tín hiệu giao dịch được kích hoạt sẽ được thực hiện ngay lập tức.
Khi chiến lược ngôn ngữ Pine được thực hiện từ trái sang phải trên biểu đồ, K-bar trên biểu đồ được chia thành历史BarVà实时Barcủa:
-
Lịch sử Bar
Khi chiến lược được thiết lập là "Mô hình giá thực" bắt đầu thực hiện, tất cả các K-bar trên biểu đồ ngoại trừ một K-bar ở bên phải nhất
历史Bar◦ Lập luận chiến lược trong mỗi cột历史BarChỉ thực hiện một lần.
Khi chiến lược được thiết lập là "Mô hình giá đóng cửa" bắt đầu thực hiện, tất cả các Bar trên biểu đồ đều là历史Bar◦ Lập luận chiến lược trong mỗi cột历史BarChỉ thực hiện một lần.Tính toán dựa trên lịch sử Bar:
Mã chiến lược được thực hiện một lần trong trạng thái đóng lịch sử Bar, sau đó mã chiến lược tiếp tục được thực hiện trong lịch sử Bar tiếp theo cho đến khi tất cả các lịch sử Bar được thực hiện một lần. -
Bar thời gian thực
Khi chiến lược được thực hiện trên Bar K cuối cùng ở bên phải, Bar đó là Bar thời gian thực. Khi Bar thời gian thực đóng cửa, Bar này sẽ trở thành một Bar thời gian thực đã qua (thay đổi thành Bar lịch sử).
Khi chiến lược được đặt thành "Mô hình giá thời gian thực" bắt đầu thực hiện, mỗi lần thay đổi hành động trên thanh thời gian thực sẽ thực hiện một logic chiến lược.
Khi chiến lược được đặt thành "Mô hình giá đóng cửa" bắt đầu thực hiện, biểu đồ sẽ không hiển thị Bar thực.Dựa trên tính toán của Bar:
Nếu thiết lập chiến lược là "Mô hình giá đóng cửa" biểu đồ không hiển thị Bar thực tế, mã chiến lược chỉ được thực hiện một lần khi Bar hiện tại đóng cửa.
Nếu thiết lập một chiến lược là "mô hình giá cổ phiếu thực" thì tính toán và lịch sử Bar trên thực tế Bar hoàn toàn khác nhau, mỗi lần thay đổi hành động trên Bar thực tế sẽ thực hiện một mã chiến lược. Ví dụ: biến tích hợphigh、low、closeTrong lịch sử Bar là xác định, trong thời gian thực Bar có thể mỗi khi hành động thay đổi những giá trị này sẽ thay đổi. Vì vậy, các chỉ số dựa trên các giá trị tính toán dữ liệu cũng sẽ thay đổi trong thời gian thực.closeNó luôn luôn là giá hiện tại.highVàlowLuôn đại diện cho các điểm cao nhất và thấp nhất đạt được kể từ khi Bar hiện tại bắt đầu. Các biến tích hợp này đại diện cho các giá trị cuối cùng khi Bar hiện tại được cập nhật lần cuối.Cơ chế quay trở lại khi thực hiện chiến lược trên Bar thời gian thực (trong mô hình giá thời gian thực):
Trong thực hiện Bar trong thời gian thực, mỗi lần lặp lại của chiến lược thực hiện biến định nghĩa của người dùng trước khi đặt lại được gọi là quay trở lại. Để hiểu cơ chế quay trở lại bằng một ví dụ, chúng ta hãy kiểm tra mã như sau.Để ý:
/*backtest ... .. . */Nội dung của gói là thông tin cấu hình phản hồi được lưu trữ dưới dạng mã trên nền tảng FMZ.
pine/*backtest start: 2022-06-03 09:00:00 end: 2022-06-08 15:00:00 period: 1m basePeriod: 1m exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}] */ var n = 0 if not barstate.ishistory runtime.log("n + 1之前, n:", n, " 当前bar_index:", bar_index) n := n + 1 runtime.log("n + 1之后, n:", n, " 当前bar_index:", bar_index) plot(n, title="n")Chúng tôi chỉ xem xét các cảnh được thực hiện trong thời gian thực của Bar, vì vậy chúng tôi sử dụng
not barstate.ishistoryHạn chế biểu thức chỉ tích lũy n biến trong thời gian thực Bar và được sử dụng trước và sau khi thực hiện hoạt động tích lũyruntime.logHàm xuất thông tin trong nhật ký chính sách. Từ việc sử dụng hàm đồ họaplotĐường cong n được vẽ có thể thấy là 0 trong khi chiến lược đang ở trong lịch sử Bar chạy. Khi thực hiện đến Bar thực tế kích hoạt hoạt động n tích lũy 1, và mỗi lần thực hiện chiến lược trên Bar thực tế thực hiện n tích lũy 1. Từ thông tin nhật ký, có thể thấy rằng mỗi lần thực hiện lại mã chiến lược n được đặt lại vào giá trị mà chiến lược thực hiện Bar trước đó cuối cùng đã gửi.Tóm lại:
1 , Chiến lược thực hiện một mã chiến lược mỗi lần cập nhật tình huống khi Bar thực hiện.
2 Khi thực hiện trên Real-time Bar, mỗi lần thực hiện mã chính sách sẽ xoay ngược các biến.
3, khi thực hiện trên thực tế Bar, biến được gửi một lần khi cập nhật kết thúc.Các thao tác vẽ như đường cong trên biểu đồ cũng có thể gây ra việc vẽ lại, vì dữ liệu sẽ quay ngược, ví dụ như chúng ta sửa đổi mã thử nghiệm trước đó, thử nghiệm ổ cứng:
pinevar n = 0 if not barstate.ishistory runtime.log("n + 1之前, n:", n, " 当前bar_index:", bar_index) n := open > close ? n + 1 : n runtime.log("n + 1之后, n:", n, " 当前bar_index:", bar_index) plot(n, title="n")Bức ảnh chụp màn hình tại thời điểm A

Ảnh chụp màn hình của khoảnh khắc B

Chúng tôi chỉ sửa đổi câu này:
n := open > close ? n + 1 : n, Bar hiện tại trong thời gian thực là âm ((nghĩa là giá mở cửa cao hơn giá đóng cửa) chỉ khi n được tích lũy 1. Bạn có thể thấy rằng trong biểu đồ đầu tiên ((thời điểm A) vì giá mở cửa cao hơn giá đóng cửa ((thời điểm âm)) vì vậy n được tích lũy 1, đường cong n hiển thị giá trị là 5 . Sau đó, thay đổi, giá cập nhật như trong biểu đồ thứ hai ((thời điểm B) hiển thị. -
Variable trong hàm context
Dưới đây chúng ta cùng nghiên cứu các biến trong hàm ngôn ngữ Pine. Theo mô tả trên một số hướng dẫn của Pine, các biến trong hàm khác với các biến ngoài hàm như sau:
Lịch sử của các biến chuỗi được sử dụng trong hàm Pine được tạo ra bằng mỗi lần gọi liên tiếp của hàm. Nếu không có hàm được gọi trên mỗi cột trong kịch bản, điều này sẽ dẫn đến sự khác biệt giữa các giá trị lịch sử của chuỗi bên trong và bên ngoài khối hàm. Do đó, nếu không có hàm được gọi trên mỗi cột, các chuỗi được sử dụng cùng một giá trị chỉ mục trong và bên ngoài hàm sẽ không tham khảo cùng một điểm lịch sử.
Có gì khó hiểu không? Không có vấn đề gì, chúng tôi đã tìm hiểu vấn đề này bằng cách chạy một đoạn mã thử nghiệm trên FMZ:
pine/*backtest start: 2022-06-03 09:00:00 end: 2022-06-08 15:00:00 period: 1m basePeriod: 1m exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}] */ f(a) => a[1] f2() => close[1] oneBarInTwo = bar_index % 2 == 0 plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A") plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B") plot(close[2], title = "close[2]", color = color.red, overlay = true) plot(close[1], title = "close[1]", color = color.green, overlay = true)Chụp ảnh chụp lại hoạt động
Mã kiểm tra khá đơn giản, chủ yếu là để xem xét dữ liệu được trích dẫn theo hai cách, đó là:
f(a) => a[1]Vàf2() => close[1]。-
f(a) => a[1]: cách sử dụng tham số truyền, hàm cuối cùng trả vềa[1]。 -
f2() => close[1]: Sử dụng biến tích hợp trực tiếpcloseFunction cuối cùng được trả về.close[1]。
[]Biểu tượng được sử dụng để tham chiếu các giá trị lịch sử của các biến trong chuỗi dữ liệu, close[1] là trích dẫn dữ liệu giá đóng cửa trên Bar trước giá đóng cửa hiện tại.-
plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A")
Vẽ một ký tự từ A đến B, màu đỏ, chỉ vẽ khi oneBarInTwo là đúng, và vị trí vẽ trên trục Y là:f(close)Giá trị trả về: -
plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
Vẽ một ký tự B<unk>, màu xanh lá cây, khi oneBarInTwo là đúng, và vị trí của nó (trên trục Y) là:f2()Giá trị trả về: -
plot(close[2], title = "close[2]", color = color.red, overlay = true)
Đường vẽ, màu đỏ, vị trí vẽ (trên trục Y) là:close[2]Đó là giá đóng cửa trên Bar hiện tại số 2 trước của Bar ((2 số trái của Bar)). -
plot(close[1], title = "close[1]", color = color.green, overlay = true)
Đường vẽ, màu xanh lá cây, vị trí vẽ (trên trục Y) là:close[1]Đó là giá đóng cửa trên Bar hiện tại.
Các chức năng được sử dụng cho các thẻ vẽ A mặc dù bạn có thể nhìn thấy các hình ảnh chụp hoạt động của chiến lược phản hồi
f(a) => a[1]và các hàm được sử dụng để đánh dấu Bf2() => close[1]Tất cả đều được sử dụng.[1] để tham khảo dữ liệu lịch sử trên chuỗi dữ liệu, nhưng vị trí của dấu "A" và "B" trên biểu đồ hoàn toàn khác nhau. Vị trí của dấu "A" luôn nằm trên đường màu đỏ, tức là mã trong chiến lượcplot(close[2], title = "close[2]", color = color.red, overlay = true)Dưới đây là một ví dụ về một con số được vẽ trên một đường và sử dụng nó để vẽ một đường.close[2]。Lý do là chỉ mục của K-lineBar, tức là biến tích hợp
bar_indexTính liệu có vẽ dấu "A" và "B" không. Chữ "A" và "B" không được vẽ trên mỗi thanh K.f(a) => a[1]Giá trị được trích dẫn theo cách này sẽ tương ứng với hàm nếu hàm không được gọi trên mỗi Bar.f2() => close[1]Các giá trị được trích dẫn theo cách này khác nhau[1] cùng một chỉ mục như vậy) [2]. -
-
Một số hàm tích hợp cần được tính trên mỗi Bar để tính đúng kết quả của nó
Một ví dụ đơn giản cho thấy điều này:
pineres = close > close[1] ? ta.barssince(close < close[1]) : -1 plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)Chúng ta sẽ gọi hàm
ta.barssince(close < close[1])Viết trong một toán tử ba chiềucondition ? value1 : value2Điều này dẫn đến việc chỉ cóclose > close[1]Khi gọi hàm ta.barssince.ta.barssinceChức năng được tính từ lần gần nhấtclose < close[1]Số lượng dòng K khi tạo ra. Khi gọi hàm ta.barssince, tất cả các hàm đều là close > close[1], tức là giá đóng cửa hiện tại lớn hơn giá đóng cửa của Bar trước đó, khi hàm ta.barssince được gọi thì điều kiện của nó là close < close[1] không được thành lập, và không có vị trí thành lập gần đây nhất.ta.barssince: Khi được gọi, hàm này sẽ trả về na。 nếu điều kiện này chưa bao giờ được đáp ứng trước dòng K hiện tại.
Như thể hiện trong hình:
Vì vậy, khi vẽ, chúng ta chỉ vẽ dữ liệu khi biến res có giá trị ((-1) }}.
Để tránh vấn đề này, chúng ta chỉ cần sử dụng
ta.barssince(close < close[1])Gọi hàm lấy từ toán tử tri, viết bên ngoài bất kỳ nhánh điều kiện nào có thể. Cho phép nó thực hiện tính toán trên mỗi dòng K Bar.a = ta.barssince(close < close[1]) res = close > close[1] ? a : -1 plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)
Dòng thời gian
Khái niệm về trình tự thời gian rất quan trọng trong ngôn ngữ Pine, và là một khái niệm chúng ta phải hiểu khi học ngôn ngữ Pine. trình tự thời gian không phải là một loại mà là cấu trúc cơ bản để lưu trữ các giá trị liên tục của các biến theo thời gian, chúng ta biết rằng kịch bản Pine dựa trên biểu đồ, và nội dung cơ bản nhất được hiển thị trong biểu đồ là biểu đồ K. trình tự thời gian trong đó mỗi giá trị được liên kết với mốc thời gian của một thanh K.openlà một biến trong ngôn ngữ Pine (built-in), cấu trúc của nó là một chuỗi thời gian để lưu trữ giá mở cửa của mỗi dòng K Bar. Nó có thể được hiểu làopenCấu trúc trình tự thời gian này đại diện cho giá mở của tất cả các Bar của K trong K hiện tại từ Bar đầu tiên bắt đầu đến Bar hiện tại. Nếu K hiện tại là chu kỳ 5 phút, chúng tôi sẽ trích dẫn trong mã chiến lược Pine (hoặc sử dụng)openGiá mở cửa của K-Line Bar khi sử dụng mã chiến lược hiện tại. Nếu muốn tham khảo các giá trị lịch sử trong chuỗi thời gian, cần sử dụng[]Điều khiển: Khi chính sách Pine được thực hiện trên một K-line Bar, nó được sử dụngopen[1]Hiển thị trích dẫnopenGiá mở đầu của K-bar trước của K-bar hiện tại của kịch bản hiện tại trong chuỗi thời gian ((đó là giá mở đầu của K-bar trước).
-
Các biến trên chuỗi thời gian rất dễ tính toán
Chúng ta có một hàm tích hợpta.cumVí dụ:ta.cum Cumulative (total) sum of `source`. In other words it's a sum of all elements of `source`. ta.cum(source) → series float RETURNS Total sum series. ARGUMENTS source (series int/float) SEE ALSO math.sumMã kiểm tra:
pinev1 = 1 v2 = ta.cum(v1) plot(v1, title="v1") plot(v2, title="v2") plot(bar_index+1, title="bar_index")Có rất nhiều tương tự
ta.cumCác hàm tích hợp như vậy có thể xử lý trực tiếp dữ liệu trên chuỗi thời gian, chẳng hạn nhưta.cumChúng ta có thể sử dụng một biểu đồ để dễ hiểu hơn.Hướng dẫn hoạt động của chiến lược
| - | - | - | - |
Chiến lược này được thực hiện trên đường K-bar 0 và 1 và 1.
Chiến lược này được thực hiện trên đường K-bar thứ hai là 1, 2, 3.
Chiến lược này được thực hiện trên đường thứ ba, K-bar, và nó có 2 và 1 và nó có 3.
|...|...|...|...|
Chiến lược này được thực hiện trên n+1 gốc K, n-thanh, n-thanh, n-thanh.Bạn có thể thấy rằng v1, v2 và thậm chí bar_index đều là cấu trúc theo trình tự thời gian, mỗi Bar có dữ liệu tương ứng. Mã thử nghiệm này không phân biệt giữa mô hình giá thực hoặc mô hình giá đóng cửa chỉ để hiển thị Bar thực trên biểu đồ. Để đo lại tốc độ, chúng tôi sử dụng thử nghiệm phản hồi mô hình giá đóng cửa.
Vì biến v1 trên mỗi thanh là 1
ta.cum(v1)Khi hàm được thực hiện trên dòng Bar đầu tiên của K, vì chỉ có dòng Bar đầu tiên, nó được tính là 1, và được gán giá trị cho biến v2.
Khita.cum(v1)Khi thực hiện trên Bar K thứ hai, đã có 2 Bar K ((bar_index của biến nén tương ứng đầu tiên là 0, bar_index của biến nén tương ứng thứ hai là 1), vì vậy kết quả tính toán là 2, gán giá trị cho biến v2, v.v.). Thực tế có thể thấy rằng v2 là số lượng Bar K trong biểu đồ, vì chỉ số của Kbar_indexVậy là chúng ta có thể bắt đầu từ 0.bar_index + 1Thực tế là số lượng của dòng K.v2Vàbar_indexNó là sự trùng hợp.Tôi cũng có thể sử dụng
ta.cumChức năng này sẽ tính tổng giá trị đóng cửa của tất cả các Bar trên biểu đồ hiện tại, và chỉ có thể viết như sau:ta.cum(close), khi chiến lược chạy đến thanh thời gian thực ở bên phảita.cum(close)Kết quả tính toán là tổng giá đóng cửa của tất cả các Bar trên biểu đồ (không chạy đến bên phải, chỉ cộng thêm vào Bar hiện tại).Các biến trên chuỗi thời gian cũng có thể được tính toán bằng các toán tử, chẳng hạn như mã:
ta.sma(high - low, 14)và thay đổi các biến tronghigh(K-line Bar giá cao nhất) trừ đilow(Giá thấp nhất của K-Line Bar), sử dụng cuối cùngta.smaChức năng tìm trung bình. -
Kết quả gọi hàm cũng để lại dấu vết của giá trị trong chuỗi thời gian
v1 = ta.highest(high, 10)[1] v2 = ta.highest(high[1], 10) plot(v1, title="v1", overlay=true) plot(v2, title="v2", overlay=true)Mã thử nghiệm này được thực hiện khi thử nghiệm lại và có thể quan sát thấy
v1Vàv2Các giá trị của các hàm là giống nhau, và các đường được vẽ trên biểu đồ cũng trùng khớp hoàn toàn. Các kết quả tính toán của hàm gọi sẽ để lại dấu vết của các giá trị trong chuỗi thời gian, chẳng hạn như mãta.highest(high, 10)[1]Trong số đó,ta.highest(high, 10)Kết quả tính toán của hàm gọi cũng có thể được sử dụng[1] để trích dẫn giá trị lịch sử của nó.ta.highest(high, 10)Kết quả là:ta.highest(high[1], 10)Vì thế.ta.highest(high[1], 10)Vàta.highest(high, 10)[1]Giá tương đương.Chứng thực thông tin đầu ra bằng hàm phác họa khác:
a = ta.highest(close, 10)[1] b = ta.highest(close[1], 10) plotchar(true, title="a", char=str.tostring(a), location=location.abovebar, color=color.red, overlay=true) plotchar(true, title="b", char=str.tostring(b), location=location.belowbar, color=color.green, overlay=true)Bạn có thể thấy các giá trị của biến a và biến b trong chuỗi thời gian được hiển thị ở trên và dưới Bar tương ứng. Bạn có thể giữ mã vẽ này trong quá trình học, vì khi kiểm tra, thử nghiệm, thông tin có thể thường xuyên cần xuất trên biểu đồ để quan sát.
Cấu trúc kịch bản
Cấu trúc chung
Trong phần đầu của hướng dẫn, chúng tôi đã tóm tắt một số điểm khác nhau về việc sử dụng ngôn ngữ Pine trên FMZ và trên Trading View.indicator()、strategy()Và, tạm thời, không hỗ trợ.library()Tất nhiên, để tương thích với phiên bản trước của kịch bản Pine, khi viết chiến lược, hãy viết những điều như://@version=5,indicator(),strategy()Một số thiết lập chính sách cũng có thể được cài đặt trong các trang web khác.strategy()Cài đặt tham số truyền trong hàm ◦
<version>
<declaration_statement>
<code>
<version>Thông tin kiểm soát phiên bản có thể bị bỏ qua.
Ghi chú
Ngôn ngữ Pine//Cụm chú thích đơn dòng, bởi vì ngôn ngữ Pine không có chú thích đa dòng./**/Nó được sử dụng cho nhiều dòng chú thích.
Mã
Một câu lệnh có thể là một trong những nội dung này.
- Tuyên bố biến
- Đặt lại giá trị của biến
- Tuyên bố hàm
- Gọi hàm được xây dựng, gọi hàm được định nghĩa bởi người dùng
if,for,whilehoặcswitchCấu trúc
Các câu có thể được sắp xếp theo nhiều cách
- Một số câu lệnh có thể được thể hiện bằng một dòng, chẳng hạn như hầu hết các tuyên bố biến, chỉ chứa một dòng gọi hàm hoặc tuyên bố hàm một dòng. Những người khác, như cấu trúc, luôn cần nhiều dòng vì chúng cần một khối địa phương.
- Các câu nói trong phạm vi toàn cầu của kịch bản (tức là những phần không thuộc khối địa phương) không thể được coi là
空格hoặc制表符(Tab) bắt đầu. Các ký tự đầu tiên của chúng cũng phải là ký tự đầu tiên của dòng. Các dòng bắt đầu ở vị trí đầu tiên của dòng, theo định nghĩa trở thành một phần của phạm vi toàn cầu của kịch bản. - Một cấu trúc hay một hàm đa dòng luôn cần một
local blockMột khối địa phương phải được thu nhỏ thành một dấu biểu thức hoặc bốn khoảng trống (trừ khi nó được phân tích thành chuỗi liên kết của dòng trước, tức là được coi là nội dung liên tục của dòng trước), mỗi khối địa phương xác định một phạm vi địa phương khác nhau. - Nhiều câu đơn hàng có thể được nối tiếp trong một dòng bằng cách sử dụng dấu chấm ký ức ((,) làm dấu phân cách.
- Một dòng có thể chứa các chú thích, hoặc chỉ là chú thích.
- Các dòng cũng có thể được gói lại (như tiếp tục trên nhiều dòng).
Ví dụ, bao gồm ba khối địa phương, một trong các tuyên bố hàm tùy chỉnh và hai trong các tuyên bố biến sử dụng cấu trúc if, như sau:
pine
indicator("", "", true) // 声明语句(全局范围),可以省略不写
barIsUp() => // 函数声明(全局范围)
close > open // 本地块(本地范围)
plotColor = if barIsUp() // 变量声明 (全局范围)
color.green // 本地块 (本地范围)
else
color.red // 本地块 (本地范围)
runtime.log("color", color = plotColor) // 调用一个内置函数输出日志 (全局范围)
Thay đổi mã
Các dòng dài có thể được chia thành nhiều dòng hoặc được "bọc" lên. Các dòng được bọc phải được thu hẹp vào bất kỳ số lượng khoảng trống nào, miễn là nó không phải là nhân của 4 (các biên giới này được sử dụng để thu hẹp vào các khối cục bộ).
pine
a = open + high + low + close
Có thể được đóng gói thành (lưu ý rằng số khoảng trống mỗi dòng không phải là nhân của 4):
pine
a = open +
high +
low +
close
Một cuộc gọi plot (()) dài có thể được đóng gói thành ▽.
pine
close1 = request.security(syminfo.tickerid, "D", close) // syminfo.tickerid 当前交易对的日线级别收盘价数据系列
close2 = request.security(syminfo.tickerid, "240", close) // syminfo.tickerid 当前交易对的240分钟级别收盘价数据系列
plot(ta.correlation(close, open, 100), // 一行长的plot()调用可以被包装
color = color.new(color.purple, 40),
style = plot.style_area,
trackprice = true)
Các câu trong tuyên bố hàm được định nghĩa bởi người dùng cũng có thể được đóng gói. Tuy nhiên, vì khối địa phương phải bắt đầu bằng dấu rút gọn theo ngữ pháp ((4 khoảng trống hoặc 1 biểu tượng), khi chia nó thành hàng tiếp theo, phần tiếp tục của câu phải bắt đầu bằng một hoặc nhiều dấu rút gọn ((không bằng số nhân của 4 khoảng trống). Ví dụ:
pine
test(c, o) =>
ret = c > o ?
(c > o+5000 ?
1 :
0):
(c < o-5000 ?
-1 :
0)
a = test(close, open)
plot(a, title="a")
Biểu thức và toán tử
Biểu tượng
Trước khi hiểu về biến, chúng ta cần hiểu khái niệm về ký tự nhận diện hàm.chức năngVàBiến sốTên của ((được sử dụng để đặt tên cho biến, hàm) <unk>chức năngChúng ta sẽ tìm hiểu trong các bài học tiếp theo, chúng ta sẽ bắt đầu bằng việc học các ký hiệu nhận diện <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk> <unk>
-
- Nhãn hiệu phải được viết bằng chữ cái lớn
(A-Z)Hoặc viết nhỏ(a-z)Chữ hoặc gạch chéo(_)Bắt đầu, là ký tự đầu tiên trong nhận dạng.
- Nhãn hiệu phải được viết bằng chữ cái lớn
- 2, ký tự tiếp theo sau ký tự đầu tiên có thể làChữ cái、Gạch dướihoặcSố liệu。
- 3, tên của biểu tượng được viết bằng chữ viết lớn và chữ viết nhỏ.
Ví dụ như tên của các biểu tượng:
pine
fmzVar
_fmzVar
fmz666Var
funcName
MAX_LEN
max_len
maxLen
3barsDown // 错误的命名!使用了数字字符作为标识符的开头字符
Giống như hầu hết các ngôn ngữ lập trình khác, ngôn ngữ Pine cũng có đề xuất viết. Thường được đề xuất khi đặt tên cho các định danh:
- 1, toàn bộ chữ cái được viết to để đặt tên cho hằng số.
-
- Sử dụngQuy tắc Hồ HàmTên gọi cho các định danh khác.
pine
// 命名变量、常量
GREEN_COLOR = #4CAF50
MAX_LOOKBACK = 100
int fastLength = 7
// 命名函数
zeroOne(boolValue) => boolValue ? 1 : 0
Máy tính
Các toán tử là một số ký hiệu hoạt động trong ngôn ngữ lập trình được sử dụng để xây dựng biểu thức, và biểu thức là quy tắc tính toán được thiết kế cho một số mục đích tính toán khi chúng ta viết chiến lược. Các toán tử trong ngôn ngữ Pine được phân loại theo chức năng:
Các toán tử định giá, toán tử số, toán tử so sánh, toán tử logic,? : Máy tính ba chiều.[]Hoạt động trích dẫn lịch sử.
Các toán tử tính toán*Ví dụ, để phân biệt các loại vấn đề do kết quả trả về của toán tử ngôn ngữ Pine trên Trading View, có mã kiểm tra sau:
pine
//@version=5
indicator("")
lenInput = input.int(14, "Length")
factor = year > 2020 ? 3 : 1
adjustedLength = lenInput * factor
ma = ta.ema(close, adjustedLength) // Compilation error!
plot(ma)
Nếu bạn có thể làm điều này, bạn sẽ nhận được một lỗi biên dịch khi chạy kịch bản này trên Trình xem giao dịch vì:adjustedLength = lenInput * factorSau khi nhân, chúng ta sẽ cóseries intTuy nhiên,ta.emaCác tham số thứ hai của hàm không hỗ trợ loại này. Tuy nhiên, trên FMZ không có những hạn chế nghiêm ngặt như vậy, các mã trên có thể hoạt động bình thường.
Sau đây chúng ta sẽ xem xét cách sử dụng các toán tử khác nhau.
Điều toán định giá
Có hai loại toán tử định giá:=、:=Chúng ta đã thấy nó trong một vài ví dụ ở phần đầu của bài học.
=Hoạt động được sử dụng để ban đầu hóa hoặc tuyên bố giá trị cho biến.=Các biến sau khi định giá sẽ bắt đầu với giá trị đó trên mỗi Bar sau đó. Đây là các tuyên bố biến có hiệu lực:
a = close // 使用内置变量赋值给a
b = 10000 // 使用数值赋值
c = "test" // 使用字符串赋值
d = color.green // 使用颜色值赋值
plot(a, title="a")
plot(b, title="b")
plotchar(true, title="c", char=str.tostring(c), color=d, overlay=true)
Để ýa = closeĐịnh nghĩa định giá, trong mỗi Bar biến a là giá đóng cửa hiện tại của Bar đó ((close) ⋅ các biến khácb、c、dNó không thay đổi, có thể được thử nghiệm trong hệ thống phản hồi trên FMZ, và kết quả có thể được nhìn thấy từ bản đồ.
:=Nó được sử dụng để gán lại giá trị cho một biến hiện có, có thể được hiểu đơn giản là sử dụng:=Các toán tử được sử dụng để thay đổi giá trị của các biến đã được khai báo và khởi tạo.
Nếu sử dụng:=Hình thức gán giá trị cho một biến chưa được khởi tạo hoặc tuyên bố sẽ gây ra lỗi, ví dụ:
pine
a := 0
Vì vậy,:=Các toán tử định giá thường được sử dụng để định giá lại các biến đã có, ví dụ:
pine
a = close > open
b = 0
if a
b := b + 1
plot(b)
Xác địnhclose > open(tức là BAR hiện tại là đường dương) và biến a là giá trị thực ((true)) sẽ thực hiện mã trong khối địa phương của câu nói ifb := b + 1, sử dụng toán tử định giá:=Đặt giá trị lại cho b, cộng thêm một 1 ◦ và sau đó sử dụng hàm plot để vẽ trên biểu đồ các giá trị của biến b trên mỗi BAR trong chuỗi thời gian, kết nối các dòng ◦
Chúng ta có nghĩ rằng nếu có một trục BAR, b sẽ tiếp tục tích lũy 1 không? Tất nhiên là không, ở đây chúng ta không sử dụng bất kỳ từ khóa nào khi chúng ta tuyên bố biến b và khởi tạo nó là 0b=0Vì vậy, bạn có thể thấy rằng kết quả của việc chạy mã này là mỗi lần b được đặt lại là 0 nếu a là giá trị thực.close > openVì vậy, khi thực hiện vòng mã này, b sẽ cộng 1, khi vẽ hàm plot, b là 1, nhưng khi thực hiện vòng mã tiếp theo, b sẽ được định giá lại là 0. Đây cũng là nơi mà người mới bắt đầu ngôn ngữ Pine dễ bị mắc kẹt.
Nói về toán tử định giá, chúng ta phải mở rộng về hai từ khóa:var、varip
-
var
Từ khóa này, chúng ta đã thấy và sử dụng trong các hướng dẫn trước đó, nhưng chúng ta không tìm hiểu chi tiết về nó.
var là từ khóa được sử dụng để phân bổ và khởi tạo biến một lần. Thông thường, ngữ pháp gán giá trị biến mà không bao gồm từ khóa var sẽ dẫn đến giá trị biến được che phủ mỗi khi dữ liệu được cập nhật. Ngược lại, khi sử dụng từ khóa var để phân bổ biến, chúng vẫn có thể giữ trạng thái trơ trẽn mặc dù dữ liệu được cập nhật
Chúng ta vẫn dùng ví dụ này, nhưng chúng ta dùng nó khi chúng ta định giá cho b.
varTừ khóa:pinea = close > open var b = 0 if a b := b + 1 plot(b)varTừ khóa cho phép biến b chỉ thực hiện định giá ban đầu lần đầu tiên, sau đó không đặt lại b là 0 mỗi khi thực hiện logic chính sách, vì vậy từ đường vẽ khi chạy có thể quan sát được b, tức là số lượng đường dương BAR đã xuất hiện khi đo lại đường K hiện tại BAR.Các biến trong tuyên bố var không chỉ có thể được viết trong phạm vi toàn cầu mà còn có thể được viết trong các khối mã, ví dụ như ví dụ này:
pinestrategy(overlay=true) var a = close var b = 0.0 var c = 0.0 var green_bars_count = 0 if close > open var x = close b := x green_bars_count := green_bars_count + 1 if green_bars_count >= 10 var y = close c := y plot(a, title = "a") plot(b, title = "b") plot(c, title = "c")Biến số 'a' giữ giá đóng cửa của cột đầu tiên trong chuỗi.
Biến số 'b' giữ giá đóng cửa của thanh giá thạch anh xanh đầu tiên trong chuỗi.
Biến số 'c' giữ giá đóng cửa của 10 quả khoai tây xanh trong chuỗi. -
varip
varipChúng ta có thể nhìn thấy từ khóa này lần đầu tiên, và chúng ta có thể thấy mô tả của từ khóa này:varip ((var intrabar persist) là từ khóa được sử dụng để phân bổ và khởi tạo biến một lần. Nó tương tự như từ khóa var, nhưng biến sử dụng tuyên bố varip giữ giá trị của nó giữa các bản cập nhật K-line trong thời gian thực.
Có khó hiểu hơn không? Không sao, chúng tôi sẽ giải thích bằng ví dụ, rất dễ hiểu.
strategy(overlay=true) // 测试 var varip var i = 0 varip ii = 0 // 将策略逻辑每轮改变的i、ii打印在图上 plotchar(true, title="ii", char=str.tostring(ii), location=location.abovebar, color=color.red) plotchar(true, title="i", char=str.tostring(i), location=location.belowbar, color=color.green) // 每轮逻辑执行都给i、ii递增1 i := i + 1 ii := ii + 1Mã thử nghiệm này hoạt động khác nhau trên mô hình giá đóng cửa và mô hình giá thực tế:
Mô hình giá thực tế:
Bạn có nhớ chúng tôi đã nói trước đây rằng khi thực hiện chiến lược, chúng ta sẽ phân chia thời gian thành thời gian BAR lịch sử và thời gian BAR thực?var、varipBiến số tuyên bối、iiMỗi lần thực hiện mã chiến lược sẽ thực hiện các hoạt động gia tăng. Vì vậy, bạn có thể thấy rằng các con số được hiển thị trên đường KBAR của kết quả đo lường lại đều tăng dần 1. Khi giai đoạn K-line lịch sử kết thúc, giai đoạn K-line thời gian thực bắt đầu. Các biến trong tuyên bố var, varip bắt đầu thay đổi.i := i + 1Vàii := ii + 1Tất cả sẽ được thực hiện một lần. Sự khác biệt là ii sẽ được sửa đổi mỗi lần. Mặc dù i cũng được sửa đổi mỗi lần, nhưng nó sẽ khôi phục giá trị trước đó khi thực hiện chiến lược logic vòng tiếp theo (nhớ cơ chế cuộn màng mà chúng tôi đã giải thích trong chương "Hiến pháp thực hiện mô hình" trước đây?) cho đến khi dòng KBAR hiện tại được hoàn thành để cập nhật giá trị xác định của i (nghĩa là không còn khôi phục giá trị trước khi thực hiện chiến lược logic vòng tiếp theo).Mô hình giá đóng cửa:
Vì mô hình giá đóng cửa chỉ thực hiện một logic chiến lược khi mỗi dòng K BAR đi qua. Vì vậy, trong mô hình giá đóng cửa, giai đoạn K-đường lịch sử và giai đoạn K-đường thời gian thực, các biến trong tuyên bố var, varip trong ví dụ trên đã tăng lên hoàn toàn, mỗi dòng K-đường BAR tăng lên 1.
Máy tính toán số
| Máy tính | minh họa |
|---|---|
| + | Thêm |
| - | Phương pháp trừ |
| * | Nhân |
| / | Phá bỏ luật |
| % | Tìm gương mẫu |
+、-Các toán tử có thể được sử dụng như các toán tử nhị phân hoặc một toán tử đơn vị. Các toán tử số khác chỉ có thể được sử dụng như các toán tử nhị phân, nếu được sử dụng như một toán tử đơn vị sẽ bị lỗi.
1, toán tử số là cả hai bên là loại giá trị số, kết quả là loại giá trị số, nguyên loại hoặc số điểm nổi tùy thuộc vào kết quả hoạt động.
2, nếu trong số đó có một số là một chuỗi, thì hàm là+Nếu là một toán tử số khác, nó sẽ cố gắng chuyển đổi chuỗi thành giá trị số và sau đó hoạt động.
3, Nếu số hoạt động trong đó là na, kết quả tính là giá trị không na, sẽ hiển thị NaN khi in trên FMZ.
pine
a = 1 + 1
b = 1 + 1.1
c = 1 + "1.1"
d = "1" + "1.1"
e = 1 + na
runtime.log("a:", a, ", b:", b, ", c:", c, ", d:", d, ", e:", e)
// a: 2 , b: 2.1 , c: 11.1 , d: 11.1 , e: NaN
Ngôn ngữ Pine trên FMZ có một chút khác biệt so với ngôn ngữ Pine trên Trading View, ngôn ngữ Pine trên FMZ không quá khắc nghiệt về yêu cầu loại biến. Ví dụ:
pine
a = 1 * "1.1"
b = "1" / "1.1"
c = 5 % "A"
plot(a)
plot(b)
plot(c)
Nó có thể được thực hiện trên FMZ, nhưng sẽ báo cáo lỗi kiểu trên giao dịch xem. Đối với các toán tử số toán là chuỗi, hệ thống sẽ chuyển đổi chuỗi thành giá trị số sau khi tính toán. Nếu chuỗi không có giá trị không thể được tính toán, hệ thống kết quả hoạt động sẽ là giá trị không na.
So sánh toán tử
Các toán tử so sánh là các toán tử nhị phân.
| Máy tính | minh họa |
|---|---|
| < | Ít hơn |
| > | Hơn |
| <= | nhỏ hơn bằng |
| >= | Lớn hơn bằng |
| == | Tương đương |
| != | Sự bất bình đẳng |
Ví dụ kiểm tra:
pine
a = 1 > 2
b = 1 < 2
c = "1" <= 2
d = "1" >= 2
e = 1 == 1
f = 2 != 1
g = open > close
h = na > 1
i = 1 > na
runtime.log("a:", a, ", b:", b, ", c:", c, ", d:", d, ", e:", e, ", f:", f, ", g:", g, ", h:", h, ", i:", i)
// a: false , b: true , c: true , d: false , e: true , f: true , g: false , h: false , i: false
Bạn có thể thấy rằng điều khiển so sánh rất đơn giản, nhưng nó cũng là điều khiển chúng ta sử dụng nhiều nhất khi viết chiến lược. Bạn có thể so sánh cả các giá trị và các biến tích hợp, ví dụ:close、openChờ đợi.
Cũng giống như các điều khiển hoạt động, trên FMZ có sự khác biệt với Pine trong Trading View, FMZ không có loại yêu cầu đặc biệt nghiêm ngặt, vì vậy các câu nói như vậyd = "1" >= 2 Trên FMZ không có báo lỗi, khi thực hiện, chuỗi sẽ được chuyển đổi thành giá trị số trước khi so sánh. Trên Trading View sẽ báo lỗi.
Các toán tử logic
| Máy tính | Biểu tượng mã | minh họa |
|---|---|---|
| Không | not | Là một toán tử, không phải là một toán tử |
| Và | and | Hoạt động nhị phân, với (và) |
| hoặc | or | Các toán tử nhị phân, hoặc các toán tử |
Nói về toán tử logic, thì chắc chắn phải nói về bảng giá trị thực. Cũng giống như chúng ta học ở trường trung học, chỉ là ở đây chúng ta thử nghiệm và học trong hệ thống phản hồi:
pine
a = 1 == 1 // 使用比较运算符构成的表达式,结果为布尔值
b = 1 != 1
c = not b // 逻辑非操作符
d = not a // 逻辑非操作符
runtime.log("测试逻辑操作符:and", "#FF0000")
runtime.log("a:", a, ", c:", c, ", a and c:", a and c)
runtime.log("a:", a, ", b:", b, ", a and b:", a and b)
runtime.log("b:", b, ", c:", c, ", b and c:", b and c)
runtime.log("d:", d, ", b:", b, ", d and b:", d and b)
runtime.log("测试逻辑操作符:or", "#FF0000")
runtime.log("a:", a, ", c:", c, ", a or c:", a or c)
runtime.log("a:", a, ", b:", b, ", a or b:", a or b)
runtime.log("b:", b, ", c:", c, ", b or c:", b or c)
runtime.log("d:", d, ", b:", b, ", d or b:", d or b)
runtime.error("stop")
Để không bị ảnh hưởng bởi việc hệ thống phản hồi liên tục in thông tin, chúng tôi sử dụngruntime.error("stop")Câu nói sau khi thực hiện một lần in, chỉ cần ném lỗi bất thường để kết nối dừng lại, sau đó bạn có thể quan sát thông tin đầu ra, bạn có thể thấy rằng nội dung in và bảng giá trị thực là giống nhau.
Máy tính ba chiều
Sử dụng toán tử ba chiều? : Biểu thức ba chiều kết hợp với số hoạt độngcondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseChúng ta cũng đã quen thuộc với nó trong các bài học trước đây. Các biểu thức ba chiều, các toán tử ba chiều có nghĩa là tổng số các hoạt động của nó là ba.
condition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseTrong,conditionĐiều kiện phán quyết là nếu giá trị của biểu thức thực là:valueWhenConditionIsTrueNếuconditionGiá trị của biểu thức giả làvalueWhenConditionIsFalse。
Ví dụ, mặc dù không có nhiều ứng dụng thực tế, nhưng nó rất dễ dàng để giới thiệu:
pine
a = close > open
b = a ? "阳线" : "阴线"
c = not a ? "阴线" : "阳线"
plotchar(a, location=location.abovebar, color=color.red, char=b, overlay=true)
plotchar(not a, location=location.belowbar, color=color.green, char=c, overlay=true)
Các biểu thức ba chiều cũng có thể được nhúng, chúng tôi đã làm điều này trong các hướng dẫn trước đây.
pine
a = close > open
b = a ? math.abs(close-open) > 30 ? "阳线" : "十字星" : math.abs(close-open) > 30 ? "阴线" : "十字星"
c = not a ? math.abs(close-open) > 30 ? "阴线" : "十字星" : math.abs(close-open) > 30 ? "阳线" : "十字星"
plotchar(a, location=location.abovebar, color=color.red, char=b, overlay=true)
plotchar(not a, location=location.belowbar, color=color.green, char=c, overlay=true)
Điều này tương đương với việccondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseTRONGvalueWhenConditionIsTrue、valueWhenConditionIsFalse, cũng sử dụng các biểu thức ba chiều khác thay vì ▽.
Máy tính lịch sử
Sử dụng toán tử lịch sử[]Các giá trị lịch sử trên chuỗi thời gian. Các giá trị lịch sử này là giá trị trên dòng K BAR trước dòng K BAR hiện tại khi kịch bản chạy.[]Các toán tử được sử dụng sau khi gọi các biến, biểu thức và hàm.[]Giá trị trong các ô vuông này là độ lệch của dữ liệu lịch sử chúng ta muốn tham khảo từ BAR của dòng K hiện tại. Ví dụ: nếu tôi muốn tham khảo giá đóng cửa của BAR của dòng K trước đó, tôi sẽ viết như sau:close[1]。
Chúng ta đã thấy cách viết tương tự trong các bài học trước đây:
pine
high[10]
ta.sma(close, 10)[1]
ta.highest(high, 10)[20]
close > nz(close[1], open)
[]Các toán tử chỉ có thể được sử dụng một lần trên cùng một giá trị, vì vậy viết như thế là sai, sẽ trả lỗi:
pine
a = close[1][2] // 错误
Bạn có thể thấy ở đây, một số bạn học sẽ nói rằng điều khiển[]Một trong những cách tốt nhất để làm điều này là sử dụng một cấu trúc chuỗi, nó giống như một cấu trúc chuỗi (series) và một mảng!
Dưới đây là một ví dụ để giải thích sự khác biệt giữa series và array trong ngôn ngữ Pine.
pine
strategy("test", overlay=true)
a = close
b = close[1]
c = b[1]
plot(a, title="a")
plot(b, title="b")
plot(c, title="c")
Mặc dù nóia = close[1][2]Tôi không nghĩ rằng tôi có thể viết như vậy, nhưng:
pine
b = close[1]
c = b[1]
Nếu chúng ta phân tách chúng, chúng sẽ không sai, nếu chúng ta hiểu chúng theo cách mà chúng thường được hiểu, đó là một mảng.b = close[1]Sau khi định giá, b sẽ là một số, nhưngc = b[1], b vẫn có thể được sử dụng một lần nữa để sử dụng các nhà điều hành lịch sử để tham khảo các giá trị lịch sử. Các khái niệm về chuỗi trong ngôn ngữ Pine không đơn giản như mảng. Nó có thể được hiểu là giá trị lịch sử trên Bar gần nhất (được gán giá trị cho b), b cũng là một cấu trúc chuỗi thời gian (được gán chuỗi thời gian), có thể tiếp tục tham khảo các giá trị lịch sử của nó.
Chúng ta có thể kéo biểu đồ về phía bên trái nhất, và thấy rằng trên dòng K đầu tiên, giá trị của b và c đều là giá trị không ((na). Đó là bởi vì khi kịch bản được thực hiện trên dòng BAR đầu tiên của K, không có giá trị lịch sử khi trích dẫn một hoặc hai chu kỳ về phía trước, nó không tồn tại. Vì vậy, chúng ta cần phải thường xuyên chú ý khi viết chiến lược để xem liệu giá trị không được trích dẫn khi trích dẫn dữ liệu lịch sử, nếu không cẩn thận sử dụng giá trị không có giá trị sẽ gây ra một loạt các tính toán khác nhau, thậm chí có thể ảnh hưởng đến thời gian thực.na、nzChúng tôi đã làm điều này trong một bài học trước.nz、naChức năng, bạn có nhớ ở chương nào không?) đặc biệt xử lý các trường hợp không có giá trị, ví dụ:
pine
close > nz(close[1], open) // 当引用close内置变量前一个BAR的历史值时,如果不存在,则使用open内置变量
Đây là một cách xử lý các giá trị null có thể được tham chiếu là ((na)).
Ưu tiên đ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 bằng các kết hợp khác nhau của các số và các phép toán. Vậy thì khi tính toán trong biểu thức, các hoạt động này được ưu tiên như thế nào? Giống như hoạt động bốn quy tắc mà chúng ta học khi đi học, có phép nhân trước phép trừ, sau đó tính toán phép cộng trừ.
| Ưu tiên | Máy tính |
|---|---|
| 9 | [] |
| 8 | + 、 - `` và not `` |
| 7 | *、/、% |
| 6 | +, ```- `` |
| 5 | >、<、>=、<= |
| 4 | ==、!= |
| 3 | and |
| 2 | or |
| 1 | ?: |
Các phần biểu thức có ưu tiên cao được thực hiện trước, và nếu ưu tiên giống nhau thì được thực hiện từ trái sang phải. Nếu bạn muốn bắt buộc một phần được thực hiện trước, bạn có thể sử dụng()Gói biểu thức bắt buộc phải tính toán phần đó trước.
Biến số
Tuyên bố biến
Chúng ta đã học được khái niệm về ký hiệu <unk>, ký hiệu <unk> là tên được đặt cho một biến như là tên của một biến. Vì vậy, chúng ta có thể nói rằng: biến là ký hiệu của giá trị được lưu giữ. Vậy làm thế nào để tuyên bố một biến?
-
Mô hình tuyên bố:
Mô hình khai báo biến (declaration mode) được viết đầu tiên khi khai báo biến. Có ba kiểu khai báo biến:- Sử dụng từ khóa
var。 - Sử dụng từ khóa
varip。
3, Không viết gì cả.
var、varipCác từ khóa mà chúng ta đã học ở phần "chương trình định giá" trước đây, không được đề cập ở đây. Nếu mô hình tuyên bố của biến không viết gì, ví dụ như câu:i = 1Trong thực tế, chúng tôi đã nói trước đó, biến được tuyên bố như vậy và được gán giá trị, được thực hiện trên mỗi dòng KBAR. - Sử dụng từ khóa
-
kiểu
Ngôn ngữ Pine trên FMZ không nghiêm ngặt đối với yêu cầu kiểu, thường có thể bỏ qua. Tuy nhiên, để tương thích với chiến lược kịch bản trên Trading View, biến thể cũng có thể có kiểu khi tuyên bố. Ví dụ:int i = 0 float f = 1.1Loại trên Trading View là yêu cầu nghiêm ngặt hơn, nếu sử dụng mã sau trên Trading View sẽ bị lỗi:
baseLine0 = na // compile time error! -
Biểu tượng
Biểu tượng là tên biến, tên của biểu tượng đã được đề cập trong chương trước, bạn có thể xem lại: https://www.fmz.com/bbs-topic/9390#标识符
Tóm lại, tuyên bố một biến có thể được viết như sau:
// [<declaration_mode>] [<type>] <identifier> = value
声明模式 类型 标识符 = 值
Các nhà điều hành định giá được sử dụng ở đây:=Đặt giá trị cho một biến trong một tuyên bố biến. Đặt giá trị cho một biến có thể là một chuỗi, một giá trị, một biểu thức, một hàm gọi, hoặc một hàm khác.if、 for、whilehoặcswitchCác cấu trúc khác ((các cấu trúc từ khóa, câu nói sử dụng chúng tôi sẽ giải thích chi tiết trong các bài học tiếp theo, thực tế chúng tôi đã học được trong các bài học trước đây về việc gán giá trị câu nói if đơn giản, bạn có thể xem lại))
Ở đây chúng ta sẽ tập trung vào hàm input, một hàm mà chúng ta thường xuyên sử dụng khi thiết kế và lập trình các chiến lược.
hàm input:
input函数,参数defval、title、tooltip、inline、group
Chức năng input trên FMZ và trên Trading View hơi khác nhau, nhưng chức năng này được sử dụng như đầu vào được gán cho các tham số chiến lược. Dưới đây chúng ta sẽ chi tiết hơn về cách sử dụng chức năng input trên FMZ bằng một ví dụ:
pine
param1 = input(10, title="参数1名称", tooltip="参数1的描述信息", group="分组名称A")
param2 = input("close", title="参数2名称", tooltip="参数2的描述信息", group="分组名称A")
param3 = input(color.red, title="参数3名称", tooltip="参数3的描述信息", group="分组名称B")
param4 = input(close, title="参数4名称", tooltip="参数4的描述信息", group="分组名称B")
param5 = input(true, title="参数5名称", tooltip="参数5的描述信息", group="分组名称C")
ma = ta.ema(param4, param1)
plot(ma, title=param2, color=param3, overlay=param5)
Trong FMZ, hàm input sẽ tự động vẽ ra các điều khiển để thiết lập tham số chính sách. Các điều khiển được hỗ trợ trên FMZ hiện có hộp nhập giá trị, hộp nhập văn bản, hộp kéo xuống, và chọn giá trị. Ngoài ra, bạn có thể thiết lập các nhóm tham số chính sách, thông tin văn bản nhắc để thiết lập tham số và các chức năng khác.
Chúng tôi giới thiệu một số tham số chính của hàm input:
- defval: là giá trị mặc định cho các tùy chọn tham số chính sách được đặt cho hàm đầu vào, hỗ trợ các biến, giá trị và chuỗi được xây dựng trong ngôn ngữ Pine
- title: là tên tham số mà chính sách hiển thị trên giao diện chính sách của ổ đĩa/đánh giá.
- tooltip: Thông tin gợi ý về tham số chính sách, hiển thị thông tin văn bản về thiết lập tham số này khi chuột treo trên tham số chính sách.
- group: là tên của một nhóm tham số chính sách, có thể được đặt cho các nhóm tham số.
Ngoài việc khai báo và gán giá trị cho các biến riêng lẻ, ngôn ngữ Pine còn có cách viết để khai báo một tập hợp các biến và gán giá trị:
[变量A,变量B,变量C] = 函数 或者 ```if```、 ```for```、```while```或```switch```等结构
Chúng ta thường sử dụngta.macdKhi hàm tính MACD, MACD là một chỉ số đa dòng, tính ba nhóm dữ liệu. Vì vậy, nó có thể được viết là:
pine
[dif,dea,column] = ta.macd(close, 12, 26, 9)
plot(dif, title="dif")
plot(dea, title="dea")
plot(column, title="column", style=plot.style_histogram)
Chúng ta có thể dễ dàng vẽ đồ thị MACD bằng cách sử dụng các mã trên, không chỉ hàm tích hợp có thể trả về nhiều biến mà hàm tùy chỉnh được viết cũng có thể trả về nhiều dữ liệu.
pine
twoEMA(data, fastPeriod, slowPeriod) =>
fast = ta.ema(data, fastPeriod)
slow = ta.ema(data, slowPeriod)
[fast, slow]
[ema10, ema20] = twoEMA(close, 10, 20)
plot(ema10, title="ema10", overlay=true)
plot(ema20, title="ema20", overlay=true)
Việc sử dụng cấu trúc if như là một định giá cho nhiều biến cũng tương tự như cách thức hàm tùy chỉnh ở trên, bạn cũng có thể thử.
[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ã cục bộ có nhánh điều kiện, chủ yếu là các hàm sau:
barcolor(), fill(), hline(), indicator(), plot(), plotcandle(), plotchar(), plotshape()
Trading View sẽ biên soạn báo cáo lỗi. Hạn chế trên FMZ không nghiêm ngặt, nhưng cũng khuyên bạn nên viết theo quy định trên Trading View. Ví dụ: mặc dù không báo cáo lỗi trên FMZ, nhưng không khuyên bạn nên viết như vậy.
pine
strategy("test", overlay=true)
if close > open
plot(close, title="close")
else
plot(open, title="open")
Câu if
Ví dụ:
pine
var lineColor = na
n = if bar_index > 10 and bar_index <= 20
lineColor := color.green
else if bar_index > 20 and bar_index <= 30
lineColor := color.blue
else if bar_index > 30 and bar_index <= 40
lineColor := color.orange
else if bar_index > 40
lineColor := color.black
else
lineColor := color.red
plot(close, title="close", color=n, linewidth=5, overlay=true)
plotchar(true, title="bar_index", char=str.tostring(bar_index), location=location.abovebar, color=color.red, overlay=true)
Ghi chú: Các biểu thức dùng để đánh giá, trả về giá trị boolean. Cẩn thận thu nhỏ. Chỉ có một chi nhánh else.
pine
x = if close > open
close
plot(x, title="x")
Vì khi K line BAR là âm, tức là khi close < open, thì if biểu thức sau câu nói là false, thì không thực hiện khối mã cục bộ của if. Tại thời điểm này cũng không có nhánh else, câu nói if sẽ trả về na. . . . . . . . . . . . . . . . . . . . . . . . . .
Cụm từ switch
Câu lệnh switch cũng là một câu lệnh có cấu trúc phân nhánh, được sử dụng để thiết kế thực hiện các con đường khác nhau theo một số điều kiện. Các câu lệnh switch nói chung có một số điểm kiến thức quan trọng sau đây:
1, câu lệnh switch cũng có thể trả về giá trị như câu lệnh if.
2, không giống như các câu lệnh chuyển đổi trong các ngôn ngữ khác, khi thực hiện cấu trúc chuyển đổi, chỉ thực hiện một khối cục bộ trong mã của nó, vì vậy tuyên bố phá vỡ 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 switch 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 tập hợp các giá trị)). Nếu không có bất kỳ nhánh nào của khối mã cục bộ được thực hiện, nó sẽ trả về na。
4. Xác định vị trí biểu thức trong cấu trúc chuyển đổi, có thể viết chuỗi, biến, biểu thức hoặc hàm gọi.
5. switch cho phép chỉ định một giá trị trả về, giá trị này được sử dụng như giá trị mặc định khi không có điều kiện khác trong cấu trúc.
Switch có hai dạng, chúng ta hãy xem từng ví dụ để biết cách sử dụng chúng.
1, có biểu thứcswitchVí dụ:
pine
// input.string: defval, title, options, tooltip
func = input.string("EMA", title="指标名称", tooltip="选择要使用的指标函数名称", options=["EMA", "SMA", "RMA", "WMA"])
// input.int: defval, title, options, tooltip
// param1 = input.int(10, title="周期参数")
fastPeriod = input.int(10, title="快线周期参数", options=[5, 10, 20])
slowPeriod = input.int(20, title="慢线周期参数", options=[20, 25, 30])
data = input(close, title="数据", tooltip="选择使用收盘价、开盘价、最高价...")
fastColor = color.red
slowColor = color.red
[fast, slow] = switch func
"EMA" =>
fastLine = ta.ema(data, fastPeriod)
slowLine = ta.ema(data, slowPeriod)
fastColor := color.red
slowColor := color.red
[fastLine, slowLine]
"SMA" =>
fastLine = ta.sma(data, fastPeriod)
slowLine = ta.sma(data, slowPeriod)
fastColor := color.green
slowColor := color.green
[fastLine, slowLine]
"RMA" =>
fastLine = ta.rma(data, fastPeriod)
slowLine = ta.rma(data, slowPeriod)
fastColor := color.blue
slowColor := color.blue
[fastLine, slowLine]
=>
runtime.error("error")
plot(fast, title="fast" + fastPeriod, color=fastColor, overlay=true)
plot(slow, title="slow" + slowPeriod, color=slowColor, overlay=true)
Trước đây chúng ta đã học các hàm input, và ở đây chúng ta tiếp tục học các hàm tương tự như input:input.string、input.intchức năng.
input.stringNó có thể được sử dụng để trả về một chuỗi.input.intChức năng này được sử dụng để trả về giá trị nguyên tố. Trong ví dụ này, thực sự đã thêm mộtoptionsDùng các tham số,optionsCác tham số có thể được truyền vào một mảng có giá trị có thể chọn. Ví dụ như trong ví dụoptions=["EMA", "SMA", "RMA", "WMA"]Vàoptions=[5, 10, 20](Lưu ý rằng một là loại chuỗi và một là loại giá trị số). Như vậy, các điều khiển trên giao diện chính sách sẽ không cần phải nhập các giá trị cụ thể, nhưng điều khiển trở thành hộp kéo xuống, chọn các tùy chọn được cung cấp trong tham số options.
Các giá trị của biến func là một chuỗi, biến func là biểu thức của switch (có thể là biến, hàm gọi, biểu thức), để xác định nhánh nào trong switch được thực hiện. Nếu biến func không thể khớp với biểu thức trên bất kỳ nhánh nào trong switch (tức là tương đương), thì thực hiện khối mã nhánh mặc định, sẽ thực hiệnruntime.error("error")Chức năng gây ra chính sách ném ngoại lệ dừng.
Trong mã thử nghiệm của chúng tôi ở trên, chúng tôi không thêm runtime.error sau dòng cuối cùng của khối mã nhánh mặc định của switch[Mã như na, na] để tương thích với giá trị trả về, trên trading view cần phải xem xét vấn đề này, nếu loại không phù hợp sẽ bị lỗi. Tuy nhiên, trên FMZ không có loại yêu cầu nghiêm ngặt, vì vậy có thể bỏ qua mã tương thích này. Vì vậy, trên FMZ không cần xem xét vấn đề tương thích loại của giá trị trả về if, switch branch.
pine
strategy("test", overlay=true)
x = if close > open
close
else
"open"
plotchar(true, title="x", char=str.tostring(x), location=location.abovebar, color=color.red)
Không có lỗi trên FMZ, nhưng có lỗi trên trading view. Bởi vì if chi nhánh trả về loại không phù hợp.
- Không có biểu hiện
switch
Chúng ta sẽ xem tiếp.switchMột cách khác sử dụng từ "của" là viết không có biểu thức.
pine
up = close > open // up = close < open
down = close < open
var upOfCount = 0
var downOfCount = 0
msgColor = switch
up =>
upOfCount += 1
color.green
down =>
downOfCount += 1
color.red
plotchar(up, title="up", char=str.tostring(upOfCount), location=location.abovebar, color=msgColor, overlay=true)
plotchar(down, title="down", char=str.tostring(downOfCount), location=location.belowbar, color=msgColor, overlay=true)
Ví dụ mã thử nghiệm cho thấy rằng switch sẽ phù hợp với điều kiện thực hiện chi nhánh là khối mã cục bộ thực sự. Nói chung, các điều kiện chi nhánh sau câu lệnh chuyển đổi phải là đối nghịch nhau. Đó là nói rằng trong ví dụ trên và dưới không thể đồng thời là đúng. Vì switch chỉ có thể thực hiện một khối mã cục bộ của chi nhánh, người quan tâm có thể đưa câu này vào mã:up = close > open // up = close < open Chuyển đổi thành các chú thích, kiểm tra lại các kết quả sau khi quan sát. Bạn sẽ thấy rằng nhánh switch chỉ thực hiện nhánh đầu tiên. Ngoài ra, bạn cần lưu ý rằng bạn không nên gọi hàm vào nhánh của switch, hàm không thể được gọi trên mỗi BAR có thể gây ra một số vấn đề về tính toán dữ liệu.switchTrong ví dụ này, nhánh thực thi được xác định và sẽ không thay đổi trong hoạt động của chiến lược).
Cấu trúc vòng tròn
for câu
返回值 = for 计数 = 起始计数 to 最终计数 by 步长
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
Các câu lệnh for rất đơn giản để sử dụng, vòng lặp for có thể cuối cùng trả về một giá trị ((), hoặc trả về nhiều giá trị, để[a, b, c] như vậy). Như các biến được gán cho vị trí "giả giá trị" trong mã giả trên. Các câu lệnh for được theo sau bởi một biến "đếm" được sử dụng để kiểm soát số lần vòng lặp, tham khảo các giá trị khác, v.v. Định biến "đếm" được gán là "đếm ban đầu" trước khi vòng quay bắt đầu, sau đó tăng dần theo cài đặt "chặng" và vòng quay dừng lại khi biến "đếm" lớn hơn "đếm cuối cùng".
được sử dụng trong vòng lặp forbreakTừ khóa: khi thực hiệnbreakMột người đàn ông có thể nói rằng: "Tôi không thể làm được điều này".
được sử dụng trong vòng lặp forcontinueTừ khóa: khi thực hiệncontinueSau khi nói, vòng tròn sẽ bỏ qua.continueSau đó, code sẽ thực hiện vòng lặp tiếp theo. Các câu lệnh for trả về giá trị trả về khi thực hiện vòng lặp cuối cùng. Nếu không có bất kỳ code nào được thực hiện, nó sẽ trả về giá trị không.
Dưới đây là một ví dụ đơn giản:
pine
ret = for i = 0 to 10 // 可以增加by关键字修改步长,暂时FMZ不支持 i = 10 to 0 这样的反向循环
// 可以增加条件设置,使用continue跳过,break跳出
runtime.log("i:", i)
i // 如果这行不写,就返回空值,因为没有可返回的变量
runtime.log("ret:", ret)
runtime.error("stop")
for ... in câu
for ... inCâu nói có hai dạng, dưới đây là mã giả để giải thích.
返回值 = for 数组元素 in 数组
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
返回值 = for [索引变量, 索引变量对应的数组元素] in 数组
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
Có thể thấy rằng sự khác biệt chính giữa hai dạng là nội dung sau từ khóa for, một là sử dụng một biến để tham chiếu các phần tử của mảng. Một là sử dụng một cấu trúc chứa các biến chỉ mục, các biến của mảng để tham chiếu.
pine
testArray = array.from(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
for ele in testArray // 修改成 [i, ele]的形式:for [i, ele] in testArray , runtime.log("ele:", ele, ", i:", i)
runtime.log("ele:", ele)
runtime.error("stop")
Sử dụng chỉ mục khi cần thiếtfor [i, ele] in testArrayCách viết của <unk>.
Ứng dụng vòng lặp
Khi bạn có thể sử dụng hàm tích hợp của ngôn ngữ Pine để thực hiện một số tính toán logic vòng lặp, bạn có thể viết trực tiếp bằng cấu trúc vòng lặp hoặc xử lý bằng hàm tích hợp. Chúng tôi đưa ra hai ví dụ.
1, tính trung bình
Khi sử dụng thiết kế cấu trúc tuần hoàn:
pine
length = 5
var a = array.new(length)
array.push(a, close)
if array.size(a) >= length
array.remove(a, 0)
sum = 0
for ele in a
sum += ele
avg = sum / length
plot(avg, title="avg", overlay=true)
Trong ví dụ này, chúng ta sử dụng phép cộng vòng lặp for, sau đó tính trung bình.
Tính trung bình được tính trực tiếp bằng hàm tích hợp:
pine
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Sử dụng chức năng tích hợp trực tiếpta.sma, tính toán chỉ số đường trung bình, rõ ràng là để tính toán đường trung bình sử dụng hàm tích hợp đơn giản hơn. Trong biểu đồ so sánh có thể thấy kết quả tính toán hoàn toàn phù hợp.
- Ghi âm
Hoặc sử dụng ví dụ trên để giải thích.
Khi sử dụng thiết kế cấu trúc tuần hoàn:
pine
length = 5
var a = array.new(length)
array.push(a, close)
if array.size(a) >= length
array.remove(a, 0)
sum = 0
for ele in a
sum += ele
avg = sum / length
plot(avg, title="avg", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Bạn cũng có thể sử dụng hàm tích hợp để tính tổng của tất cả các phần tử trong mảng.array.sumHãy tính toán.
Tính toán cộng trực tiếp bằng hàm tích hợp:
pine
length = 5
var a = array.new(length)
array.push(a, close)
if array.size(a) >= length
array.remove(a, 0)
plot(array.sum(a) / length, title="avg", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Bạn có thể thấy các dữ liệu được tính toán, sử dụng plot vẽ trên biểu đồ hiển thị hoàn toàn phù hợp.
Vì vậy, nếu bạn có thể thực hiện tất cả những điều này với các hàm được xây dựng sẵn, tại sao lại thiết kế vòng lặp?
1 . Đối với một số hoạt động của mảng, tính toán .
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. Vì điểm cao của BAR hiện tại chỉ được biết trên BAR của kịch bản đang chạy, nên cần một vòng lặp để quay trở lại và phân tích BAR trong quá khứ.
3 , trường hợp hàm tích hợp trong ngôn ngữ Pine không thể thực hiện tính toán cho BAR trong quá khứ.
Câu while
whileCụm từ cho phép đoạn code của 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à false (false) <unk>
返回值 = while 判断条件
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
Các quy tắc khác của while tương tự như vòng lặp for, dòng cuối cùng của khối mã cục bộ của vòng lặp là giá trị trả về, có thể trả về nhiều giá trị. Khi "điều kiện vòng" thực hiện vòng lặp là thời gian thực, điều kiện dừng lại khi vòng lặp là giả. Trong vòng lặp cũng có thể sử dụng các câu break, tiếp tục.
Tôi cũng sẽ dùng ví dụ về tính toán đường trung bình:
pine
length = 10
sma(data, length) =>
i = 0
sum = 0
while i < 10
sum += data[i]
i += 1
sum / length
plot(sma(close, length), title="sma", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Trong khi sử dụng vòng lặp cũng rất đơn giản, bạn cũng có thể thiết kế một số logic tính toán không thể thay thế bằng hàm tích hợp, ví dụ như tính toán nhân bậc:
pine
counter = 5
fact = 1
ret = while counter > 0
fact := fact * counter
counter := counter - 1
fact
plot(ret, title="ret") // ret = 5 * 4 * 3 * 2 * 1
Nhóm
Array trong ngôn ngữ Pine tương tự như định nghĩa của array trong các ngôn ngữ lập trình khác. Array của Pine là một mảng chiều. Nó thường được sử dụng để lưu trữ một chuỗi dữ liệu liên tục. Các mảng trong đó các dữ liệu cá nhân được lưu trữ được gọi là các phần tử của mảng, các loại các phần tử này có thể là: kiểu toàn bộ, kiểu nổi, chuỗi, giá trị màu, giá trị Boolean.[]Chúng ta cần phải sử dụngarray.get()Vàarray.set()Chức năng △ là thứ tự chỉ mục của các phần tử trong mảng, nghĩa là phần tử đầu tiên của mảng được chỉ mục 0, phần tử tiếp theo được chỉ mục tăng 1 △.
Chúng tôi sẽ sử dụng một mã đơn giản để giải thích:
pine
var a = array.from(0)
if bar_index == 0
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1])
else if bar_index == 1
array.push(a, bar_index)
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1])
else if bar_index == 2
array.push(a, bar_index)
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1], ", 向前数2根BAR上的a,即a[2]值:", a[2])
else if bar_index == 3
array.push(a, bar_index)
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1], ", 向前数2根BAR上的a,即a[2]值:", a[2], ", 向前数3根BAR上的a,即a[3]值:", a[3])
else if bar_index == 4
// 使用array.get 按索引获取元素,使用array.set按索引修改元素
runtime.log("数组修改前:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))
array.set(a, 1, 999)
runtime.log("数组修改后:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))
Array tuyên bố
sử dụngarray<int> a、float[] bMột mảng có thể được gán cho một mảng thông báo hoặc chỉ thông báo một biến, ví dụ:
pine
array<int> a = array.new(3, bar_index)
float[] b = array.new(3, close)
c = array.from("hello", "fmz", "!")
runtime.log("a:", a)
runtime.log("b:", b)
runtime.log("c:", c)
runtime.error("stop")
Thường được sử dụng để khởi tạo biến số mảngarray.newVàarray.fromPhương thức . . Có rất nhiều hàm trong ngôn ngữ Pine tương tự như array.new liên quan đến kiểu:array.new_int()、array.new_bool()、array.new_color()、array.new_string()Chờ đợi.
Từ khóa var cũng có thể hoạt động với mô hình tuyên bố của 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. Chúng ta có thể thấy bằng một ví dụ:
pine
var a = array.from(0)
b = array.from(0)
if bar_index == 1
array.push(a, bar_index)
array.push(b, bar_index)
else if bar_index == 2
array.push(a, bar_index)
array.push(b, bar_index)
else if barstate.islast
runtime.log("a:", a)
runtime.log("b:", b)
runtime.error("stop")
Bạn có thể thấy rằng thay đổi của mảng a được xác định liên tục, không được đặt lại. Các mảng b được khởi tạo trên mỗi BAR.barstate.islastVì vậy, khi in thời gian thực vẫn chỉ có một phần tử, giá trị 0 <unk>.
Đọc và viết các phần tử trong mảng
Sử dụng array.get để lấy các phần tử trong mảng chỉ định vị trí chỉ mục, sử dụng array.set để sửa đổi các phần tử trong mảng chỉ định vị trí chỉ mục.
Đối số đầu tiên của array.get là mảng cần xử lý, đối số thứ hai là chỉ mục được chỉ định.
Các tham số đầu tiên của array.set là mảng cần xử lý, tham số thứ hai là chỉ mục được chỉ định, tham số thứ ba là phần tử cần viết.
Một ví dụ đơn giản cho thấy điều này:
pine
lookbackInput = input.int(100)
FILL_COLOR = color.green
var fillColors = array.new(5)
if barstate.isfirst
array.set(fillColors, 0, color.new(FILL_COLOR, 70))
array.set(fillColors, 1, color.new(FILL_COLOR, 75))
array.set(fillColors, 2, color.new(FILL_COLOR, 80))
array.set(fillColors, 3, color.new(FILL_COLOR, 85))
array.set(fillColors, 4, color.new(FILL_COLOR, 90))
lastHiBar = - ta.highestbars(high, lookbackInput)
fillNo = math.min(lastHiBar / (lookbackInput / 5), 4)
bgcolor(array.get(fillColors, int(fillNo)), overlay=true)
plot(lastHiBar, title="lastHiBar")
plot(fillNo, title="fillNo")
Ví dụ này khởi tạo màu xanh lá cây cơ bản, tuyên bố và khởi tạo một mảng để lưu trữ màu, sau đó cho các giá trị màu khác nhau trong sự minh bạch (sử dụng hàm color.new) [2]. Bằng cách tính khoảng cách từ BAR hiện tại đến giá trị cao nhất trong 100 chu kỳ xem xét, tính cấp độ màu.
Đi qua các phần tử của mảng
Làm thế nào để đi qua một mảng, chúng ta có thể thực hiện điều này bằng cách sử dụng các cụm từ for/for in/while mà chúng ta đã học trước đây.
pine
a = array.from(1, 2, 3, 4, 5, 6)
for i = 0 to (array.size(a) == 0 ? na : array.size(a) - 1)
array.set(a, i, i)
runtime.log(a)
runtime.error("stop")
pine
a = array.from(1, 2, 3, 4, 5, 6)
i = 0
while i < array.size(a)
array.set(a, i, i)
i += 1
runtime.log(a)
runtime.error("stop")
pine
a = array.from(1, 2, 3, 4, 5, 6)
for [i, ele] in a
array.set(a, i, i)
runtime.log(a)
runtime.error("stop")
Ba cách này đều có kết quả tương tự.
Các mảng có thể được tuyên bố trong phạm vi toàn cầu của kịch bản hoặc trong phạm vi cục bộ của hàm hoặc nhánh if
Dữ liệu lịch sử
Đối với việc sử dụng các phần tử trong mảng, cách sau đây là tương đương, chúng ta có thể thấy bằng ví dụ sau khi vẽ hai nhóm đường trên biểu đồ, hai đường trong mỗi nhóm, và giá trị của hai đường trong mỗi nhóm là hoàn toàn giống nhau.
pine
a = array.new_float(1)
array.set(a, 0, close)
closeA1 = array.get(a, 0)[1]
closeB1 = close[1]
plot(closeA1, "closeA1", color.red, 6)
plot(closeB1, "closeB1", color.black, 2)
ma1 = ta.sma(array.get(a, 0), 20)
ma2 = ta.sma(close, 20)
plot(ma1, "ma1", color.aqua, 6)
plot(ma2, "ma2", color.black, 2)
Chức năng thêm, xóa của mảng
1, hàm liên quan đến hoạt động gia tăng của mảng:
array.unshift()、array.insert()、array.push()。
2, hàm liên quan đến việc xóa mảng:
array.remove()、array.shift()、array.pop()、array.clear()。
Chúng ta sử dụng ví dụ sau để kiểm tra các hàm hoạt động thêm, xóa của các mảng này.
pine
a = array.from("A", "B", "C")
ret = array.unshift(a, "X")
runtime.log("数组a:", a, ", ret:", ret)
ret := array.insert(a, 1, "Y")
runtime.log("数组a:", a, ", ret:", ret)
ret := array.push(a, "D")
runtime.log("数组a:", a, ", ret:", ret)
ret := array.remove(a, 2)
runtime.log("数组a:", a, ", ret:", ret)
ret := array.shift(a)
runtime.log("数组a:", a, ", ret:", ret)
ret := array.pop(a)
runtime.log("数组a:", a, ", ret:", ret)
ret := array.clear(a)
runtime.log("数组a:", a, ", ret:", ret)
runtime.error("stop")
- 1












