[TOC]
Sokongan tutorial video:https://www.youtube.com/watch?v=CA3SwJQb_1g
FMZ Quant Trading Platform menyokong penulisan strategi bahasa Pine, backtesting, dan perdagangan langsung strategi bahasa Pine, dan ia serasi dengan versi bahasa Pine yang lebih rendah.Strategy Squaredi Platform Perdagangan Kuantum FMZ (FMZ.COM).
FMZ menyokong bukan sahaja bahasa Pine, tetapi juga fungsi lukisan bahasa Pine yang kuat. Pelbagai fungsi, alat yang kaya dan praktikal, pengurusan yang cekap dan mudah di platform FMZ lebih meningkatkan kelayakan strategi (skrip) Pine. Berdasarkan keserasian dengan bahasa Pine, FMZ juga memperluaskan, mengoptimumkan dan memotong bahasa Pine ke tahap tertentu. Sebelum memasuki tutorial secara rasmi, mari kita lihat apa perubahan yang telah dibuat pada bahasa Pine di FMZ berbanding versi asal.
Gambaran ringkas mengenai beberapa perbezaan yang jelas:
//@version
danstrategy
, indicator
pernyataan di awal kod tidak wajib untuk menulis, FMZ tidak menyokongimport
untuk diimportlibrary
berfungsi buat masa ini.Ia boleh dilihat bahawa beberapa strategi yang ditulis seperti ini:
//@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)
Atau tulis seperti ini:
//@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)
Pada FMZ ia boleh disederhanakan kepada:
src = 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)
Atau:
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)
Model harga penutupan dan model harga masa nyata
Pada pandangan perdagangan, kita boleh menggunakancalc_on_every_tick
parameterstrategy
fungsi untuk menetapkan skrip strategi untuk melaksanakan logik strategi dalam masa nyata apabila harga berubah setiap kali.calc_on_every_tick
parameter harus ditetapkan kepadatrue
.calc_on_every_tick
Parameter lalai ialahfalse
, iaitu, logik strategi dilaksanakan hanya apabila BAR garis K semasa strategi telah selesai sepenuhnya.
Pada FMZ, ia ditetapkan oleh parameter
Kawalan ketepatan berangka, seperti harga dan jumlah pesanan apabila strategi dilaksanakan perlu ditentukan pada FMZ Pada pandangan perdagangan, tidak ada masalah ketepatan apabila meletakkan pesanan dagangan sebenar, kerana ia hanya boleh diuji dalam simulasi. Pada FMZ, adalah mungkin untuk menjalankan strategi Pine dalam perdagangan sebenar. Kemudian strategi perlu dapat menentukan ketepatan harga dan ketepatan jumlah pesanan dari pelbagai dagangan dengan fleksibel. Tetapan ketepatan mengawal bilangan tempat perpuluhan dalam data yang berkaitan untuk mencegah data tidak memenuhi keperluan pesanan bursa dan dengan itu gagal untuk meletakkan pesanan.
Kod kontrak niaga hadapan
Jika produk dagangan di FMZ adalah kontrak, ia mempunyai dua atribut, masing-masing swap
, dan kod kontrak bergantung kepada sama ada bursa yang beroperasi mempunyai kontrak tersebut.quarter
Kod kontrak ini adalah konsisten dengan kod kontrak niaga hadapan yang ditakrifkan dalam dokumen API bahasa Javascript / python / c ++ FMZ.
Untuk tetapan lain, seperti jumlah pesanan minimum, jumlah pesanan lalai, dan lain-lain, sila rujuk pengenalan parameter pada
runtime.debug
, runtime.log
, runtime.error
digunakan untuk debugging.3 fungsi telah ditambahkan ke platform FMZ untuk debug.
runtime.debug
: Mencetak maklumat pembolehubah pada konsol, yang biasanya tidak digunakan dengan fungsi ini.
runtime.log
: output dalam log. fungsi khusus bahasa PINE di FMZ.
runtime.log(1, 2, 3, close, high, ...), Multiple parameters can be passed.
runtime.error
: Ia akan menyebabkan ralat semasa berjalan dengan mesej ralat yang ditentukan dalam parameter mesej apabila dipanggil.
runtime.error(message)
overlay
parameter dilanjutkan dalam beberapa fungsi lukisanDalam bahasa Pine di FMZ, fungsi lukisanplot
, plotshape
, plotchar
, dll telah menambahoverlay
sokongan parameter, yang membolehkan untuk menentukan lukisan pada carta utama atau sub-grafik.overlay
ditetapkan kepadatrue
untuk menarik pada carta utama, danfalse
ditetapkan untuk menarik pada sub-grafik, yang membolehkan strategi Pine di FMZ untuk menarik carta utama dan sub-grafik pada masa yang sama.
syminfo.mintick
pembolehubah terbina dalamPeralihan terbina dalamsyminfo.mintick
ditentukan sebagai nilai tick minimum untuk simbol semasa. Nilai ini boleh dikawal oleh parameter templat harga currency precision dalam syminfo.mintick
adalah 0.01.
Sebagai contoh: harga pesanan adalah 8000, arah penjualan, kuantiti adalah 1 lot (sepotong, lembaran), harga purata selepas transaksi bukan 8000, tetapi lebih rendah daripada 8000 (kos termasuk yuran pengendalian).
Apabila mula mempelajari asas-asas bahasa Pine, mungkin ada beberapa contoh arahan dan tatabahasa kod yang kita tidak biasa. Tidak kira jika anda tidak faham, kita boleh membiasakan diri dengan konsep terlebih dahulu dan memahami tujuan ujian, atau anda boleh memeriksa dokumentasi bahasa Pine di FMZ untuk arahan. Kemudian ikuti tutorial langkah demi langkah untuk membiasakan diri dengan pelbagai tatabahasa, arahan, fungsi, dan pembolehubah terbina dalam.
Apabila mula belajar bahasa Pine, sangat perlu untuk memahami konsep yang berkaitan seperti proses pelaksanaan program skrip bahasa Pine. Strategi bahasa Pine berjalan berdasarkan carta. Kita dapat memahami bahawa strategi bahasa Pine adalah satu siri pengiraan dan operasi, yang dijalankan pada carta mengikut urutan siri masa dari data tertua yang telah dimuat naik pada carta. Jumlah data yang dimuat naik carta pada mulanya adalah terhad. Dalam perdagangan sebenar, jumlah maksimum data biasanya ditentukan berdasarkan jumlah data maksimum yang dikembalikan oleh antara muka pertukaran, dan jumlah maksimum data semasa backtesting ditentukan berdasarkan data yang disediakan oleh sumber data sistem backtesting. Bar K-line paling kiri pada carta, iaitu set data pertama carta, mempunyai nilai indeks 0.bar_index
dalam bahasa Pine.
plot(bar_index, "bar_index")
Peraturanplot
fungsi adalah salah satu fungsi yang kita akan menggunakan lebih banyak pada masa akan datang. penggunaan adalah sangat mudah, ia adalah untuk menarik garis pada carta mengikut parameter input, data input adalahbar_index
, dan garisan itu dinamakan sebagaibar_index
. Ia dapat dilihat bahawa nilai baris bernama bar_index pada Bar pertama adalah 0, dan ia meningkat dengan 1 ke kanan apabila Bar meningkat.
Kerana tetapan strategi berbeza, kaedah pelaksanaan model strategi berbeza, mereka boleh dibahagikan kepada:closing price model
danreal-time price model
Kami juga telah memperkenalkan konsep mereka secara ringkas sebelum ini.
Model harga penutupan
Apabila kod strategi dilaksanakan, tempoh Bar K-garis semasa dilaksanakan sepenuhnya, dan apabila Bar K-garis ditutup, tempoh K-garis telah selesai. Pada ketika ini, logik strategi Pine dilaksanakan sekali, dan isyarat perdagangan yang dicetuskan akan dilaksanakan pada permulaan Bar K-garis seterusnya.
Model harga masa nyata
Apabila kod strategi dilaksanakan, tanpa mengira sama ada Bar K-line semasa ditutup atau tidak, logik strategi Pine akan dilaksanakan apabila pasaran berubah setiap kali, dan isyarat perdagangan yang dicetuskan akan dilaksanakan dengan segera.
Apabila strategi bahasa Pine dilaksanakan dari kiri ke kanan pada carta, Bar K-garis pada carta dibahagikan kepadaHistorical Bars
danReal-time Bars
:
Bar Bersejarah
Apabila strategi ditetapkan kepada Historical Bars
. Logik strategi dijalankan hanya sekali pada setiaphistorical bar
.
Apabila strategi ditetapkan kepada historical bars
. Logik strategi dijalankan hanya sekali pada setiaphistorical bar
.
Pengiraan berdasarkan Bars sejarah: Kod strategi dilaksanakan sekali dalam keadaan penutupan bar sejarah, dan kemudian kod strategi terus dilaksanakan di bar sejarah seterusnya sehingga semua bar sejarah dilaksanakan sekali.
Bar masa nyata
Apabila strategi dilaksanakan ke Bar K-line terakhir di sebelah kanan, Bar adalah Bar masa nyata. Selepas bar masa nyata ditutup, bar menjadi bar masa nyata yang dilalui (menjadi bar sejarah). Bar masa nyata baru akan dihasilkan di sebelah kanan carta.
Apabila strategi ditetapkan kepada
Pengiraan berdasarkan Bar masa nyata:
Jika strategi ditetapkan kepada high
, low
, close
adalah ditentukan pada Bar sejarah, dan nilai-nilai ini boleh berubah setiap kali pasaran berubah pada Bar masa nyata. oleh itu, data seperti penunjuk yang dikira berdasarkan nilai-nilai ini juga akan berubah dalam masa nyata. pada Bar masa nyata,close
sentiasa mewakili harga terkini semasa, danhigh
danlow
sentiasa mewakili titik tertinggi dan titik terendah yang dicapai sejak permulaan bar masa nyata semasa. pembolehubah terbina dalam ini mewakili nilai akhir Bar masa nyata apabila ia terakhir dikemas kini.
Mekanisme rollback apabila melaksanakan strategi pada Bar masa nyata (model harga masa nyata): Semasa pelaksanaan Bar masa nyata, menetapkan semula pembolehubah yang ditakrifkan pengguna sebelum setiap iterasi baru strategi dipanggil rollback. Mari kita memahami mekanisme rollback dengan contoh kod ujian berikut.
Perhatian:
/*backtest
...
..
.
*/
Kandungan pakej adalah maklumat konfigurasi backtest yang disimpan dalam bentuk kod pada platform FMZ.
/*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("before n + 1, n:", n, " current bar_index:", bar_index)
n := n + 1
runtime.log("after n + 1, n:", n, " current bar_index:", bar_index)
plot(n, title="n")
Kami hanya memeriksa adegan yang dilaksanakan semasa masa nyata Bars, jadi kami menggunakannot barstate.ishistory
ungkapan untuk mengehadkan pengumpulan pembolehubah n hanya dalam Bar masa nyata, dan penggunaanruntime.log
fungsi untuk mengeluarkan maklumat dalam log strategi sebelum dan selepas operasi pengumpulan.plot
, dapat dilihat bahawa n sentiasa 0 apabila strategi dijalankan dalam Bars bersejarah. Apabila Bar masa nyata dilaksanakan, operasi penambahan 1 ke n dicetuskan, dan operasi penambahan 1 ke n dilaksanakan apabila strategi dilaksanakan dalam setiap pusingan Bar masa nyata. Ia dapat diperhatikan dari mesej log bahawa n akan disetel semula ke nilai yang akhirnya dikemukakan oleh strategi pelaksanaan Bar sebelumnya apabila kod strategi dijalankan semula dalam setiap pusingan. Kemas kini nilai n akan dikemukakan apabila kod strategi dijalankan pada Bar masa nyata untuk kali terakhir, jadi anda dapat melihat bahawa nilai kurva n meningkat sebanyak 1 dengan setiap peningkatan Bar bermula dari Bar masa nyata pada carta.
Ringkasan:
Oleh kerana data rollback, operasi lukisan, seperti lengkung pada carta juga boleh menyebabkan menggambar semula.
var n = 0
if not barstate.ishistory
runtime.log("before n + 1, n:", n, " current bar_index:", bar_index)
n := open > close ? n + 1 : n
runtime.log("after n + 1, n:", n, " current bar_index:", bar_index)
plot(n, title="n")
Tangkapan skrin masa A
Tangkapan skrin masa B
Kami hanya mengubahsuai ayat:n := open > close ? n + 1 : n
, hanya menambah 1 kepada n apabila Bar masa nyata semasa adalah garis negatif (iaitu, harga pembukaan lebih tinggi daripada harga penutupan). Ia dapat dilihat bahawa dalam carta pertama (waktu A), kerana harga pembukaan lebih tinggi daripada harga penutupan (garis negatif) pada masa itu, n dikumpulkan oleh 1, dan nilai n yang dipaparkan pada kurva carta adalah 5. Kemudian pasaran berubah dan harga dikemas kini seperti yang ditunjukkan dalam carta kedua (waktu B). Pada masa ini, harga pembukaan lebih rendah daripada harga penutupan (garis positif), dan nilai n bergolak kembali tanpa meningkat 1. kurva n dalam carta juga digambar semula dengan segera, dan nilai n pada kurva adalah 4. Oleh itu, isyarat, seperti crossup dan dipaparkan pada bar masa nyata, tidak pasti dan boleh berubah.
Konteks pembolehubah dalam fungsi
Mari kita belajar pembolehubah dalam fungsi bahasa Pine bersama-sama. Menurut beberapa penerangan pada tutorial Pine, pembolehubah dalam fungsi mempunyai perbezaan berikut dari pembolehubah di luar fungsi:
Sejarah pembolehubah siri yang digunakan dalam fungsi Pine dibuat dengan setiap panggilan berturut-turut kepada fungsi. Jika fungsi tidak dipanggil pada setiap bar di mana skrip dijalankan, ini akan mengakibatkan perbezaan antara nilai sejarah siri di dalam dan di luar blok tempatan fungsi. Oleh itu, jika fungsi tidak dipanggil pada setiap bar, siri yang dirujuk di dalam dan di luar fungsi dengan nilai indeks yang sama tidak akan merujuk kepada titik sejarah yang sama.
Jangan risau, kita akan mencari tahu dengan kod ujian yang berjalan di FMZ:
/*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)
Tangkapan skrin menjalankan backtest
Kod ujian agak mudah, terutamanya untuk memeriksa data yang dirujuk oleh dua kaedah, iaitu:f(a) => a[1]
danf2() => close[1]
.
f(a) => a[1]
: Menggunakan kaedah lulus parameter, fungsi kembali kea[1]
finally.
f2() => close[1]
: Gunakan pembolehubah terbina dalamclose
secara langsung, dan fungsi kembali keclose[1]
finally.
Peraturan[]
simbol digunakan untuk merujuk kepada nilai sejarah pembolehubah siri data, dan menutup[1] merujuk kepada data harga penutupan pada Bar sebelum harga penutupan semasa.
plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A")
Menggambar watak f(close)
.
plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
Menggambar watak f2()
.
plot(close[2], title = "close[2]", color = color.red, overlay = true)
Gambar garis, warna adalah merah, dan kedudukan yang digambar (pada paksi Y) adalah:close[2]
, yang merupakan harga penutupan bar kedua sebelum bar semasa (mengira 2 bar ke kiri).
plot(close[1], title = "close[1]", color = color.green, overlay = true)
Gambar garis, warna hijau, dan kedudukan yang digambar (pada paksi Y) adalah:close[1]
, yang merupakan harga penutupan bar pertama sebelum bar semasa (mengira 1 bar ke kiri).
Ia boleh dilihat dari tangkapan skrin strategi backtesting bahawa walaupun kedua-dua fungsif(a) => a[1]
digunakan untuk menarik penanda A dan fungsif2() => close[1]
digunakan untuk menarik penanda B menggunakan [1] untuk merujuk kepada data sejarah pada siri data, kedudukan penanda plot(close[2], title = "close[2]", color = color.red, overlay = true)
, data yang digunakan untuk melukis garis adalahclose[2]
.
Sebabnya adalah untuk mengira sama ada untuk menarik penanda bar_index
. Penanda f(a) => a[1]
tidak akan sama dengan nilai yang dirujuk oleh fungsif2() => close[1]
jika fungsi tidak dipanggil pada setiap Bar (walaupun kedua-duanya menggunakan indeks yang sama seperti [1]).
Sesetengah fungsi terbina dalam perlu dikira pada setiap Bar untuk mengira hasil mereka dengan betul
Untuk menggambarkan keadaan ini dengan contoh yang mudah:
res = close > close[1] ? ta.barssince(close < close[1]) : -1
plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)
Kita tulis kod panggilan fungsita.barssince(close < close[1])
dalam pengendali ternarcondition ? value1 : value2
. Ini menyebabkan fungsi ta.barssince dipanggil hanya apabilaclose > close[1]
Tetapi...ta.barssince
fungsi adalah untuk mengira bilangan K-garis sejak kali terakhirclose < close[1]
Apabila fungsi ta.barssince dipanggil, ia sentiasa dekat > dekat[1], iaitu, harga penutupan semasa lebih besar daripada harga penutupan Bar sebelumnya. Apabila fungsi ta.barssince dipanggil, keadaan dekat < dekat [1] tidak ditubuhkan, dan tidak ada kedudukan baru-baru ini di mana ia memegang.
ta.barssince: Apabila dipanggil, fungsi mengembalikan na jika syarat tidak pernah dipenuhi sebelum K-line semasa.
Seperti yang ditunjukkan dalam carta:
Jadi apabila carta digambar, hanya data dengan nilai untuk pembolehubah res (-1) digambar.
Untuk mengelakkan masalah ini, kita hanya mengambilta.barssince(close < close[1])
fungsi panggilan keluar dari pengendali ternar dan menulisnya di luar mana-mana cawangan bersyarat yang mungkin, membuat ia menjalankan pengiraan pada setiap K-garis 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)
Konsep siri masa sangat penting dalam bahasa Pine, dan ia adalah konsep yang mesti kita fahami apabila kita belajar bahasa Pine. Siri masa bukan jenis tetapi struktur asas untuk menyimpan nilai berterusan pembolehubah dari masa ke masa. Kita tahu bahawa skrip Pine berdasarkan carta, dan kandungan yang paling asas yang dipaparkan dalam carta adalah carta K-line. Siri masa di mana setiap nilai dikaitkan dengan cap masa Bar K-line.open
adalah pembolehubah terbina dalam (terbina dalam) bahasa Pine, dan strukturnya adalah untuk menyimpan siri masa harga pembukaan setiap Bar K-garis.open
mewakili harga pembukaan semua Bar K-garis dari Bar pertama di awal carta K-garis semasa ke Bar di mana skrip semasa dijalankan.open
dalam kod strategi Pine, ia adalah harga pembukaan Bar K-garis apabila kod strategi dijalankan pada masa ini.[]
Apabila strategi Pine dilaksanakan pada bar K-garis tertentu, gunakanopen[1]
untuk merujuk kepada harga pembukaan Bar K-line sebelumnya (iaitu harga pembukaan tempoh K-line sebelumnya) yang merujuk kepadaopen
siri masa di mana bar K-garis ini sedang dijalankan oleh skrip.
Peubah pada siri masa sangat mudah untuk pengkomputeran
Mari kita ambil fungsi terbina dalamta.cum
sebagai contoh:
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.sum
Kod ujian:
v1 = 1
v2 = ta.cum(v1)
plot(v1, title="v1")
plot(v2, title="v2")
plot(bar_index+1, title="bar_index")
Terdapat banyak fungsi terbina dalam sepertita.cum
yang boleh memproses data pada siri masa secara langsung. Sebagai contoh,ta.cum
adalah pengumpulan nilai yang sepadan dengan pembolehubah yang dihantar pada setiap Bar K-line, dan seterusnya kita menggunakan carta untuk memudahkan pemahaman.
Proses operasi strategi | Berubah terbina dalam bar_index | v1 | v2 |
---|---|---|---|
Strategi berjalan pada bar K-garis pertama | 0 | 1 | 1 |
Strategi ini berjalan pada bar K-garis kedua | 1 | 1 | 2 |
Strategi berjalan pada bar K-garis ketiga | 2 | 1 | 3 |
… | … | … | … |
Strategi berjalan pada N + 1th K-garis Bar | N | 1 | N+1 |
Ia dapat dilihat bahawa v1, v2 dan bahkan bar_index adalah semua struktur siri masa, dan terdapat data yang sepadan pada setiap bar. Sama ada kod ujian menggunakan model
Kerana pembolehubah v1 adalah 1 pada setiap Bar, apabilata.cum(v1)
Fungsi ini dijalankan pada Bar K-garis pertama, hanya ada Bar pertama, jadi hasil pengiraan adalah 1 dan diberikan kepada pembolehubah v2.
Bilakahta.cum(v1)
adalah dijalankan pada bar K-garis kedua, terdapat 2 bar K-garis (bar_index pembolehubah terbina dalam yang sepadan dengan yang pertama adalah 0, dan yang kedua yang sepadan dengan bar_index pembolehubah terbina dalam adalah 1), jadi hasil pengiraan adalah 2, yang diberikan kepada pembolehubah v2, dan sebagainya.bar_index
adalah meningkat daripada 0, makabar_index + 1
Pada carta, kita juga boleh melihat bahawa garis-garisv2
danbar_index
benar-benar bertindih.
Begitu juga, saya juga boleh menggunakanta.cum
fungsi terbina dalam untuk mengira jumlah harga penutupan untuk semua Bar pada carta semasa. semua yang saya perlu lakukan adalah menulis seperti ini:ta.cum(close)
, Apabila strategi berjalan ke Bar masa nyata di sebelah kanan, hasil yang dikira olehta.cum(close)
adalah jumlah harga penutupan semua Bar pada carta (jika tidak berjalan ke sebelah kanan, ia hanya terkumpul sehingga Bar semasa).
Peralihan pada siri masa juga boleh dikira menggunakan pengendali, seperti kod:ta.sma(high - low, 14)
, tolak pembolehubah terbina dalamhigh
(harga tertinggi Bar K-line) darilow
(harga terendah Bar K-garis), dan akhirnya menggunakanta.sma
fungsi untuk mengira nilai purata.
Hasil panggilan fungsi juga akan meninggalkan jejak nilai dalam siri masa.
v1 = ta.highest(high, 10)[1]
v2 = ta.highest(high[1], 10)
plot(v1, title="v1", overlay=true)
plot(v2, title="v2", overlay=true)
Kod ujian dijalankan semasa backtesting, dan ia boleh diperhatikan bahawa nilaiv1
danv2
Hasil yang dikira oleh panggilan fungsi akan meninggalkan jejak nilai dalam siri masa, sepertita.highest(high, 10)
dalam kodta.highest(high, 10)[1]
. Hasil yang dikira oleh panggilan fungsi juga boleh menggunakan [1] untuk merujuk kepada nilai sejarahnya.ta.highest(high, 10)
yang sepadan dengan bar sebelum Bar semasa, hasil pengiraan adalahta.highest(high[1], 10)
Jadi.ta.highest(high[1], 10)
danta.highest(high, 10)[1]
adalah sama persis.
Gunakan fungsi lukisan lain untuk output pengesahan maklumat:
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)
Kita dapat melihat bahawa nilai pembolehubah a dan pembolehubah b dalam siri masa dipaparkan di atas dan di bawah Bars yang sepadan. Kita boleh menyimpan kod lukisan ini semasa proses pembelajaran, kerana kita sering perlu mengeluarkan maklumat pada carta untuk pemerhatian semasa backtesting dan eksperimen.
Dalam bahagian awal tutorial, kita telah meringkaskan beberapa perbezaan dalam menggunakan bahasa Pine pada FMZ dan Trading View.indicator()
, strategy()
, danlibrary()
Sudah tentu, untuk menjadi serasi dengan versi sebelumnya skrip Pine, strategi seperti://@version=5
, indicator()
, strategy()
Beberapa tetapan strategi juga boleh ditetapkan dengan lulus parameter dalamstrategy()
function.
<version>
<declaration_statement>
<code>
Peraturan<version>
maklumat kawalan versi boleh dihilangkan.
Bahasa Pine menggunakan//
sebagai simbol komen satu baris, kerana bahasa Pine tidak mempunyai simbol komen berbilang baris. FMZ memperluaskan simbol komen/**/
untuk komen berbilang baris.
Baris dalam skrip yang bukan komen atau arahan kompilator adalah pernyataan, yang melaksanakan algoritma skrip.
if
, for
, while
atauswitch
strukturPernyataan boleh disusun dengan pelbagai cara
space
atau ```tab` (kunci tab). Aksara pertama mereka juga mestilah aksara pertama baris. Baris yang bermula di kedudukan pertama, oleh definisi, menjadi sebahagian daripada skop global skrip.local block
. Blok tempatan mesti ditarik dengan satu tab atau empat ruang (kalau tidak, ia akan dianalisis sebagai kod yang disambung dari baris sebelumnya, iaitu dinilai sebagai kandungan berterusan baris kod sebelumnya), dan setiap blok tempatan mentakrifkan skop tempatan yang berbeza.Sebagai contoh, ia merangkumi tiga blok tempatan, satu dalam pengisytiharan fungsi tersuai, dan dua dalam pengisytiharan pembolehubah menggunakan struktur jika, seperti berikut:
indicator("", "", true) // declaration statement (global scope), can be omitted
barIsUp() => // function declaration (global scope)
close > open // local block (local scope)
plotColor = if barIsUp() // variable declaration (global scope)
color.green // local block (local scope)
else
color.red // local block (local scope)
runtime.log("color", color = plotColor) // Call a built-in function to output the log (global scope)
Garis panjang boleh dibahagikan kepada beberapa baris, atau dibalut. Garis yang dibalut mesti diletakkan dengan mana-mana bilangan ruang, selagi ia bukan kelipatan 4 (batas-batas ini digunakan untuk mengetuk blok tempatan).
a = open + high + low + close
Ia boleh dibungkus sebagai (perhatikan bahawa bilangan ruang yang ditarik setiap baris tidak boleh menjadi kelipatan 4):
a = open +
high +
low +
close
Satu panggilan plot panjang boleh dibungkus sebagai:
close1 = request.security(syminfo.tickerid, "D", close) // syminfo.tickerid daily level closing price data series for the current trading pair
close2 = request.security(syminfo.tickerid, "240", close) // syminfo.tickerid 240-minute level closing price data series for the current trading pair
plot(ta.correlation(close, open, 100), // line-long plot() calls can be wrapped
color = color.new(color.purple, 40),
style = plot.style_area,
trackprice = true)
Perkataan dalam pengisytiharan fungsi yang ditakrifkan oleh pengguna juga boleh dibungkus. Walau bagaimanapun, kerana blok tempatan mesti bermula dengan penggoresan dalam tatabahasa (4 ruang atau 1 tab), apabila membahagikannya ke baris seterusnya, kesinambungan pernyataan mesti bermula dengan lebih daripada satu penggoresan (tidak sama dengan 4 kelipatan ruang). Sebagai contoh:
test(c, o) =>
ret = c > o ?
(c > o+5000 ?
1 :
0):
(c < o-5000 ?
-1 :
0)
a = test(close, open)
plot(a, title="a")
Sebelum mengenali pembolehubah, kita mesti memahami konsep
(A-Z)
atau huruf kecil(a-z)
surat atau garis bawah(_)
sebagai aksara pertama penanda.Seperti penanda nama berikut:
fmzVar
_fmzVar
fmz666Var
funcName
MAX_LEN
max_len
maxLen
3barsDown // Wrong naming! It used a numeric character as the leading character of the marker
Seperti kebanyakan bahasa pengaturcaraan, bahasa Pine juga mempunyai cadangan penulisan.
// name variables, constants
GREEN_COLOR = #4CAF50
MAX_LOOKBACK = 100
int fastLength = 7
// name functions
zeroOne(boolValue) => boolValue ? 1 : 0
Operator adalah beberapa simbol operasi yang digunakan dalam bahasa pengaturcaraan untuk membina ungkapan, dan ungkapan adalah peraturan pengkomputeran yang direka untuk tujuan pengkomputeran tertentu apabila kita menulis strategi. Operator dalam bahasa Pine diklasifikasikan mengikut fungsi sebagai:
Operator penugasan, operator aritmatika, operator perbandingan, operator logik,? :
pengendali ternar,[]
Operator rujukan sejarah.
Mengambil pengendali aritmatika*
sebagai contoh, ia berbeza daripada masalah jenis yang disebabkan oleh hasil pulangan pengendali bahasa Pine di Trading View. Kod ujian berikut disediakan:
//@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)
Apabila menjalankan skrip ini pada Trading View, satu ralat penyusunan akan berlaku.adjustedLength = lenInput * factor
, hasilnya ialahseries int
jenis (seri), tetapi parameter kedua fungsita.ema
Tetapi tidak ada sekatan yang ketat pada FMZ, kod di atas boleh berjalan secara normal.
Mari kita lihat penggunaan pelbagai operator bersama-sama.
Terdapat 2 jenis pengendali penugasan:=
, :=
, yang telah kita lihat dalam beberapa contoh di bahagian awal tutorial.
Peraturan=
Operator digunakan untuk menetapkan nilai kepada pembolehubah apabila ia dimulakan atau diisytiharkan.=
akan bermula dengan nilai itu pada setiap Bar berikutnya. Ini adalah pengisytiharan pembolehubah yang sah:
a = close // Use built-in variables to assign values to a
b = 10000 // Use numerical assignment
c = "test" // Use string assignment
d = color.green // Use color value assignment
plot(a, title="a")
plot(b, title="b")
plotchar(true, title="c", char=str.tostring(c), color=d, overlay=true)
Perhatikan bahawa kenyataan tugasana = close
, pembolehubah a pada setiap Bar adalah harga penutupan semasa (tutup Bar).b
, c
, d
tidak berubah dan boleh diuji dalam sistem backtest di FMZ, dan hasilnya dapat dilihat pada carta.
:=
digunakan untuk menetapkan semula nilai kepada pembolehubah sedia ada.:=
Operator digunakan untuk mengubah nilai pembolehubah yang telah diisytiharkan dan dimulakan.
Jika kita menggunakan:=
Operator untuk menetapkan nilai kepada pembolehubah yang tidak dimulakan atau diisytiharkan, ia akan menyebabkan ralat, contohnya:
a := 0
Oleh itu,:=
Operator penugasan biasanya digunakan untuk menetapkan semula pembolehubah yang sedia ada, contohnya:
a = close > open
b = 0
if a
b := b + 1
plot(b)
Menghakimi jikaclose > open
(iaitu BAR semasa adalah garis positif), pembolehubah a adalah benar. Kod dalam blok tempatan if statementb := b + 1
dilaksanakan, dan pengendali tugasan:=
Kemudian kita gunakan fungsi plot untuk menggambar nilai pembolehubah b pada setiap BAR siri masa pada carta, dan menyambungkannya ke dalam garis.
Adakah kita fikir bahawa apabila garis positif BAR muncul, b akan terus terkumpul dengan 1? tentu tidak, di sini kita mengisytiharkan dan memulakan pembolehubah b sebagai 0 tanpa menggunakan sebarang penamaan kata kunci.b=0
dilaksanakan pada setiap BAR, jadi kita boleh melihat bahawa hasil kod ini adalah untuk menetapkan semula pembolehubah b kepada 0 setiap kali, jika pembolehubah a adalah benar, iaitu, selaras denganclose > open
, maka b akan ditingkatkan dengan 1 apabila kod dijalankan dalam pusingan ini, dan b adalah 1 apabila fungsi plot menarik, tetapi b ditetapkan semula kepada 0 apabila kod dijalankan dalam pusingan seterusnya.
Apabila ia datang kepada operator penugasan, kita mesti meluaskan pada dua kata kunci:var
, varip
var
Sebenarnya, kita telah melihat dan menggunakan kata kunci ini dalam tutorial sebelumnya, tetapi kita tidak membincangkannya secara terperinci pada masa itu.
var adalah kata kunci yang digunakan untuk memperuntukkan dan satu kali inisialisasi pembolehubah. Secara umum, tatabahasa penugasan pembolehubah yang tidak mengandungi kata kunci var menyebabkan nilai pembolehubah akan ditimpa setiap kali data dikemas kini. Sebaliknya, apabila pembolehubah diberikan dengan menggunakan kata kunci var, mereka boleh
menjaga keadaan walaupun kemas kini data.
Kami masih menggunakan contoh ini, tetapi kami menggunakanvar
kata kunci apabila menetapkan nilai untuk b di sini.
a = close > open
var b = 0
if a
b := b + 1
plot(b)
Peraturanvar
kata kunci membolehkan pembolehubah b untuk melaksanakan penugasan awal sahaja, dan kemudian ia tidak akan menetapkan semula b kepada 0 setiap kali logik strategi dijalankan, jadi ia boleh diperhatikan dari garis yang digambar pada masa berjalan bahawa b adalah bilangan garis positif BAR yang telah muncul apabila garis K semasa BAR telah backtested.
Peralihan yang diisytiharkan oleh var boleh ditulis bukan sahaja dalam skop global, tetapi juga dalam blok kod, seperti contoh ini:
strategy(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")
Peralihan
berlainan
Kita lihat kata kuncivarip
untuk pertama kalinya, kita boleh melihat penerangan kata kunci ini:
varp (var intrabar persist) adalah kata kunci untuk menetapkan dan satu kali inisialisasi pembolehubah. Ia serupa dengan kata kunci var, tetapi pembolehubah yang dinyatakan dengan varip mengekalkan nilai mereka apabila kemas kini K-line masa nyata.
Adakah sukar untuk difahami? Tidak kira, kami menerangkannya melalui contoh, mudah difahami.
strategy(overlay=true)
// test var varip
var i = 0
varip ii = 0
// Print the i and ii changed in each round of the strategy logic on the chart
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)
// Increment i and ii by 1 for each round of logic execution
i := i + 1
ii := ii + 1
Kod ujian ini mempunyai prestasi yang berbeza pada
Model Bar:
Adakah anda ingat bahawa pelaksanaan strategi yang kita jelaskan sebelum ini dibahagikan kepada peringkat BAR sejarah dan peringkat BAR masa nyata? dalam Bar Model, peringkat K-garis sejarah, pembolehubahi
, ii
dinyatakan dalamvar
, varip
melakukan operasi tambahan pada setiap pusingan pelaksanaan kod strategi. Oleh itu, dapat dilihat bahawa nombor yang dipaparkan pada K-line BAR hasil backtest ditingkatkan dengan 1 satu demi satu. Apabila peringkat K-line bersejarah berakhir, peringkat K-line masa nyata bermula. Peubah-peubah yang dinyatakan oleh var dan varip mula mengalami perubahan yang berbeza. Kerana ia adalah Bar Model, kod strategi akan dijalankan sekali untuk setiap perubahan harga dalam K-line BAR,i := i + 1
danii := ii + 1
Perbezaan adalah bahawa ii dimodifikasi setiap kali. Walaupun i dimodifikasi setiap kali, nilai sebelumnya akan dipulihkan apabila logik strategi dilaksanakan pada pusingan seterusnya (ingat mekanisme rollback yang kami jelaskan dalam bab sebelumnya
Model Tick: Oleh kerana Model Tick menjalankan logik strategi hanya sekali per K-line BAR. Jadi dalam model harga penutupan, pembolehubah yang dinyatakan oleh var dan varip berkelakuan sama persis dalam contoh di atas meningkat sebanyak 1 untuk setiap K-line BAR semasa peringkat K-line sejarah dan peringkat K-line masa nyata.
Pengendali | Penerangan |
---|---|
+ | Penambahan |
- | Pengurangan |
* | Perkalian |
/ | Bahagian |
% | Modul |
Peraturan+
dan-
Operator aritmatika lain hanya boleh digunakan sebagai operator binari dan ia akan melaporkan ralat jika ia digunakan sebagai operator unari.
+
, hasil pengiraan adalah rentetan, nilai akan ditukar kepada bentuk rentetan, dan kemudian rentetan dijahit bersama-sama.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
Bahasa Pine di FMZ sedikit berbeza dengan bahasa Pine di Trading View, bahasa Pine di FMZ tidak begitu ketat mengenai jenis pembolehubah.
a = 1 * "1.1"
b = "1" / "1.1"
c = 5 % "A"
plot(a)
plot(b)
plot(c)
Ia berfungsi pada FMZ, tetapi ia melaporkan ralat jenis pada Pandangan Perdagangan. Jika kedua-dua operand operator aritmetik adalah rentetan, sistem menukar rentetan kepada nilai nombor dan kemudian mengira mereka. Jika rentetan bukan nombor tidak dapat dikira, hasil operasi sistem adalah nilai sifar
Operator perbandingan adalah semua operator binari.
Pengendali | Penerangan |
---|---|
< | < |
> | > |
<= | <= |
>= | >= |
== | == |
!= | != |
Contoh ujian:
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
Seperti yang kita lihat, operator perbandingan adalah sangat mudah digunakan, tetapi ini juga adalah operator yang paling kita gunakan apabila menulis strategi. kedua-dua nilai berangka dan pembolehubah terbina dalam boleh dibandingkan, seperticlose
, open
, dan sebagainya.
Seperti dengan pengendali, terdapat perbezaan mengenai bahasa Pine antara FMZ dan Trading View.d = "1" >= 2
tidak akan melaporkan ralat pada FMZ, dan ia akan dilaksanakan dengan menukar rentetan kepada nilai terlebih dahulu dan kemudian membandingkan operasi. pada Trading View, ia akan melaporkan ralat.
Pengendali | Simbol Kod | Penerangan |
---|---|---|
Tidak | Tidak | Operator Unary, bukan operasi |
dan | dan | Operator binari, dan operasi |
atau | atau | Operator binari, atau operasi |
Apabila ia datang kepada operator logik, maka kita mesti bercakap tentang jadual nilai sebenar. sama seperti yang kita belajar di sekolah menengah, di sini kita hanya menguji dan belajar dalam sistem backtesting kita:
a = 1 == 1 // An expression formed by using comparison operators, the result is a Boolean value
b = 1 != 1
c = not b // Logical not operators
d = not a // Logical not operators
runtime.log("test the logical operator: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("test the logical operator: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")
Untuk tidak overprint mesej, kita membuang kesilapan denganruntime.error("stop")
Selepas itu, kita boleh melihat maklumat output, dan kita boleh mendapati bahawa kandungan yang dicetak sebenarnya sama dengan jadual nilai sebenar.
Ungkapan ternar menggunakan pengendali ternar? :
digabungkan dengan operandcondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
Kita juga telah menggunakannya dalam pelajaran sebelumnya. yang dipanggil ungkapan ternar, pengendali ternar bermakna terdapat tiga operand di dalamnya.
Dalamcondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
, condition
adalah syarat penghakiman. Jika benar, nilai ungkapan adalah:valueWhenConditionIsTrue
. Jikacondition
adalah false, maka nilai ungkapan adalahvalueWhenConditionIsFalse
.
Contoh demonstrasi yang mudah, walaupun tidak banyak kegunaan praktikal:
a = close > open
b = a ? "positive line" : "negative line"
c = not a ? "negative line" : "positive line"
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)
Apa yang perlu dilakukan jika kita menemui doji? tidak kira! ungkapan ternar juga boleh bersarang, seperti yang kita lakukan dalam tutorial sebelumnya.
a = close > open
b = a ? math.abs(close-open) > 30 ? "positive line" : "doji" : math.abs(close-open) > 30 ? "negative line" : "doji"
c = not a ? math.abs(close-open) > 30 ? "negative line" : "doji" : math.abs(close-open) > 30 ? "positive line" : "doji"
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)
Malah, ia sama dengan menggantikanvalueWhenConditionIsTrue
danvalueWhenConditionIsFalse
dalamcondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalse
dengan satu lagi ungkapan ternar.
Gunakan pengendali sejarah[]
untuk merujuk kepada nilai sejarah pada siri masa. nilai sejarah ini adalah nilai pembolehubah pada bar K-garis sebelum bar K-garis semasa ketika skrip sedang berjalan.[]
Operator digunakan selepas pembolehubah, ungkapan, dan panggilan fungsi.[]
Perangkai persegi adalah perpindahan data sejarah yang ingin kita rujuk dari K-line BAR semasa. Sebagai contoh, jika saya ingin mengutip harga penutupan K-line BAR terakhir, kita menulisnya sebagai:close[1]
.
Kita telah melihat sesuatu seperti ini dalam pelajaran sebelumnya:
high[10]
ta.sma(close, 10)[1]
ta.highest(high, 10)[20]
close > nz(close[1], open)
Peraturan[]
Operator hanya boleh digunakan sekali pada nilai yang sama, jadi salah untuk menulisnya seperti ini, dan kesilapan akan dilaporkan:
a = close[1][2] // error
Di sini, seseorang mungkin mengatakan bahawa pengendali[]
digunakan untuk struktur siri, nampaknya struktur siri (serangkaian) adalah sama dengan array!
Mari kita gunakan contoh untuk menggambarkan perbezaan antara siri dan array dalam bahasa 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")
a = close[1][2]
akan melaporkan ralat, tetapi:
b = close[1]
c = b[1]
Tetapi jika ditulis secara berasingan, ia tidak akan melaporkan kesilapan.b = close [1]
, b harus menjadi nilai, tetapic = b[1]
, b masih boleh digunakan untuk merujuk kepada nilai sejarah lagi dengan menggunakan operator sejarah. Ia dapat dilihat bahawa konsep siri dalam bahasa Pine tidak semudah array. Ia boleh difahami sebagai nilai sejarah pada bar terakhir dekat (ditugaskan kepada b), b juga merupakan struktur siri masa (serangkaian masa), dan hnya