Jumlah strategi sumber terbuka di TradingView adalah besar. Sangat disayangkan bahawa begitu banyak strategi, idea, dan penunjuk yang sangat baik tidak dapat digunakan dalam bot sebenar. Melihat ini, FMZ, yang komited untuk mempopularkan teknologi perdagangan kuantitatif kepada banyak peniaga, secara semula jadi tidak dapat menekan keinginan ini untuk menyelesaikan masalah!
Perkongsian pengalaman ini adalah benar-benar ditawarkan!
Jadi, selepas berjalan melalui dunia pengaturcaraan dan membangunkan kod, melalui 9 * 9 = 81 lubang, bertahan malam yang tidak terhitung jumlahnya tanpa tidur, dan menumpuk gunung tin Red Bull kosong di sudut.
Apabila ia datang kepada bahasa Pine, saya baru-baru ini belajar sendiri. tetapi untuk jujur, bahasa Pine untuk perdagangan kuantitatif adalah benar-benar mudah digunakan dan mudah dipelajari. Biar saya tulis strategi grid untuk anda:
/*backtest
start: 2021-06-01 00:00:00
end: 2022-05-23 00:00:00
period: 1h
basePeriod: 1m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
args: [["v_input_float_1",500],["v_input_string_1",2],["v_input_float_2",0.01],["v_input_int_1",20],["v_input_int_2",500],["RunMode",1,358374],["MinStock",0.001,358374]]
*/
strategy(overlay=true)
varip beginPrice = 0
var spacing = input.float(-1, title="Spacing prices")
var dir = input.string("long", title="Directions", options = ["long", "short", "both"])
var amount = input.float(-1, title="Order quantity")
var numbers = input.int(-1, title="Number of grids")
var profit = input.int(-1, title="Profit spreads") / syminfo.mintick
if spacing == -1 and amount == -1 and numbers == -1 and profit == -1
runtime.error("Parameter errors")
if not barstate.ishistory and beginPrice == 0
beginPrice := close
findTradeId(id) =>
ret = "notFound"
for i = 0 to strategy.opentrades - 1
if strategy.opentrades.entry_id(i) == id
ret := strategy.opentrades.entry_id(i)
ret
// Real-time K-line stage
if not barstate.ishistory
// Retrieve grid
for i = 1 to numbers
// Going long
direction = dir == "both" ? "long" : dir
plot(beginPrice-i*spacing, direction+str.tostring(i), color.green)
if direction == "long" and beginPrice-i*spacing > 0 and beginPrice-i*spacing < close and findTradeId(direction+str.tostring(i)) == "notFound"
strategy.order(direction+str.tostring(i), strategy.long, qty=amount, limit=beginPrice-i*spacing)
strategy.exit("exit-"+direction+str.tostring(i), direction+str.tostring(i), qty_percent=100, profit=profit)
// Going short
direction := dir == "both" ? "short" : dir
plot(beginPrice+i*spacing, direction+str.tostring(i), color.red)
if direction == "short" and beginPrice+i*spacing > close and findTradeId(direction+str.tostring(i)) == "notFound"
strategy.order(direction+str.tostring(i), strategy.short, qty=amount, limit=beginPrice+i*spacing)
strategy.exit("exit-"+direction+str.tostring(i), direction+str.tostring(i), qty_percent=100, profit=profit)
FMZ
Sudah tentu strategi ini adalah strategi grid, yang juga mempunyai kelemahan, dan ia bukan mesin percetakan wang yang selalu menang. Kuncinya bergantung pada penggunaan dan parameter. Kami akan memberi tumpuan lebih kepada cara menulis strategi dengan mudah untuk melaksanakan logik perdagangan kita sendiri, dan membuat wang dengan menulis strategi dan berdagang sendiri. Sangat keren untuk tidak meminta bantuan!
Saya akan menerangkan kepada anda semua, kod ini mudah dan mudah difahami, dengan begitu mudah untuk belajar dan menggunakan bahasa Pine, jika anda masih tidak boleh menulis strategi, maka saya akan... memberitahu anda secara terperinci!
Kandungan yang disertakan oleh/*backtest
dan*/
pada permulaan adalah kod konfigurasi backtest FMZ. Ini adalah fungsi FMZ, bukan kandungan bahasa Pine. Sudah tentu, anda boleh meninggalkan bahagian ini, dan anda akan klik kawalan parameter secara manual untuk menetapkan konfigurasi backtest dan parameter semasa backtesting.
/*backtest
start: 2021-06-01 00:00:00
end: 2022-05-23 00:00:00
period: 1h
basePeriod: 1m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
args: [["v_input_float_1",500],["v_input_string_1",2],["v_input_float_2",0.01],["v_input_int_1",20],["v_input_int_2",500],["RunMode",1,358374],["MinStock",0.001,358374]]
*/
Kod seterusnya:
strategy(overlay=true)
varip beginPrice = 0
var spacing = input.float(-1, title="Spacing prices")
var dir = input.string("long", title="Directions", options = ["long", "short", "both"])
var amount = input.float(-1, title="Order quantity")
var numbers = input.int(-1, title="Number of grids")
var profit = input.int(-1, title="Profit points") / syminfo.mintick
strategy(overlay=true)
: Ia digunakan untuk menetapkan beberapa pilihan skrip, overlay=true, iaitu untuk menetapkan nilai benar kepada parameteroverlay
, supaya apabila menggambar carta, ia digambar pada carta utama (K-garis carta adalah carta utama, ia boleh difahami begitu mudah).varip beginPrice = 0
: Peubah startPrice diisytiharkan dengan kata kunci varip dengan nilai awal 0, yang digunakan sebagai harga awal untuk grid.var spacing = input.float(-1, title="Spacing prices")
: Tetapkan parameter strategi, nama parameter adalah var dir = input.string("long", title="Directions", options = ["long", "short", "both"])
: Tetapkan parameter strategi bernama var amount = input.float(-1, title="Order quantity")
: Tetapkan parameter untuk mengawal jumlah dagangan pada setiap dagangan titik grid.var numbers = input.int(-1, title="Number of grids")
: Bilangan titik grid, menetapkan 20 adalah 20 titik grid dalam satu arah.var profit = input.int(-1, title="Profit spreads") / syminfo.mintick
: Tetapkan parameter untuk mengawal margin keuntungan setiap kedudukan titik grid sebelum menutup kedudukan.Seterusnya, lihat kod:
if spacing == -1 and amount == -1 and numbers == -1 and profit == -1
runtime.error("Parameter errors")
Ini bermakna bahawa jika mana-mana parameter seperti jarak, jumlah, nombor, dan keuntungan tidak ditetapkan, lalai adalah -1, dan strategi akan berhenti (anda tidak boleh beroperasi secara buta tanpa menetapkan parameter)
Pergilah!
if not barstate.ishistory and beginPrice == 0
beginPrice := close
Apa yang dimaksudkan di sini ialah apabila strategi berada dalam peringkat K-line masa nyata dan startPrice == 0, ubah nilai startPrice ke harga terkini semasa. Ia dapat difahami bahawa apabila strategi berjalan secara rasmi, harga semasa awal adalah harga awal grid. Kerana skrip mempunyai peringkat BAR K-line bersejarah, strategi akan melaksanakan logik sekali dalam peringkat BAR bersejarah, dan ia pasti tidak bermakna untuk mengatur grid pada BAR bersejarah.
Apakah tahap sejarah BAR?
Untuk memberikan contoh yang mudah, pada saat A, strategi mula berjalan, dan strategi memperoleh data dengan 100 K-line BARs. Seiring berjalannya masa, 100 BARs akan menjadi 101, 102... N. Apabila ia mula berjalan dari masa A, BAR ke-101 adalah peringkat K-line masa nyata, dan masa ini adalah data masa nyata terkini. Kemudian dari BAR ke-1 hingga BAR ke-100, ini adalah harga pasaran sejarah yang telah berlalu, tetapi strategi juga akan berjalan pada harga pasaran sejarah ini, jadi peringkat ini adalah peringkat K-line sejarah.
barstate.ishistory
ini adalah pembolehubah terbina dalam bahasa Pine,barstate.ishistory
adalah benar jika BAR semasa adalah BAR bersejarah, dan salah jika ia bukan BAR bersejarah. jadi apabila bukan barstate.ishistory adalah benar, ia adalah dalam peringkat K-line masa nyata.
Seterusnya, fungsi dicipta
findTradeId(id) =>
ret = "notFound"
for i = 0 to strategy.opentrades - 1
if strategy.opentrades.entry_id(i) == id
ret := strategy.opentrades.entry_id(i)
ret
Peranan fungsi ini adalah untuk mengetahui sama ada id tertentu wujud dalam semua pesanan yang kini telah membuka kedudukan. Jika terdapat panggilan fungsi findTradeId, ia akan mengembalikan ID pesanan yang sedia ada (perhatikan bahawa ID ini bukan ID pesanan bursa, ia adalah nama yang diberikan kepada pesanan oleh strategi atau difahami sebagai label), jika tidak wujud, rentetan
Langkah seterusnya adalah untuk memulakan lembaran grid:
// Real-time K-line stage
if not barstate.ishistory
// Retrieve grid
for i = 1 to numbers
// Going long
direction = dir == "both" ? "long" : dir
plot(beginPrice-i*spacing, direction+str.tostring(i), color.green)
if direction == "long" and beginPrice-i*spacing > 0 and beginPrice-i*spacing < close and findTradeId(direction+str.tostring(i)) == "notFound"
strategy.order(direction+str.tostring(i), strategy.long, qty=amount, limit=beginPrice-i*spacing)
strategy.exit("exit-"+direction+str.tostring(i), direction+str.tostring(i), qty_percent=100, profit=profit)
// Going short
direction := dir == "both" ? "short" : dir
plot(beginPrice+i*spacing, direction+str.tostring(i), color.red)
if direction == "short" and beginPrice+i*spacing > close and findTradeId(direction+str.tostring(i)) == "notFound"
strategy.order(direction+str.tostring(i), strategy.short, qty=amount, limit=beginPrice+i*spacing)
strategy.exit("exit-"+direction+str.tostring(i), direction+str.tostring(i), qty_percent=100, profit=profit)
Pergerakan untuk digunakan, dan bilangan gelung ditentukan mengikut nilai parameter nombor, iaitu jumlah pesanan yang sepadan diatur. Tetapkan arah mengikut parameter dir. Gunakan fungsi findTradeId untuk mengetahui sama ada pesanan label pada kedudukan grid semasa telah dibuka, dan hanya meletakkan pesanan yang dirancang jika tidak ada kedudukan terbuka (jika kedudukan dibuka, ia tidak boleh diulangi). Untuk meletakkan pesanan, gunakan fungsi strategi.order untuk menentukan parameter had sebagai pesanan yang dirancang. Letakkan pesanan penutupan yang sepadan semasa meletakkan pesanan yang dirancang. Perintah penutupan menggunakanstrategy.exitfungsi, menentukan parameter keuntungan, dan menentukan mata keuntungan.
Jika kita lihat pada kurva keuntungan, kita boleh lihat bahawa grid juga berisiko. Ia bukan kemenangan yang dijamin. Hanya bahawa risiko memperluaskan grid dalam skala besar adalah sedikit lebih kecil.
Jika awak tak tahu bagaimana menulis strategi dalam bahasa Pine yang mudah dipelajari dan mudah digunakan, maka saya...