Sumber daya yang dimuat... Pemuatan...

Sistem Strategi Eksekusi Sinyal TradingView lainnya

Penulis:FMZ~Lydia, Dibuat: 2022-12-15 21:23:24, Diperbarui: 2023-09-18 20:01:55

img

Sistem Strategi Eksekusi Sinyal TradingView lainnya

Pedagang yang sering menggunakan TradingView tahu bahwa TradingView dapat mendorong pesan ke platform lain. Di Digest kami dari platform FMZ, ada strategi push sinyal TradingView yang diterbitkan di perpustakaan, di mana konten pesan yang didorong ditulis dalam url permintaan, yang agak tidak fleksibel.

Skenario dan Prinsip

Beberapa pemula mungkin bingung dengan judul artikel ini dan deskripsi di atas, tidak masalah! Mari kita mulai dengan deskripsi yang jelas tentang skenario dan prinsip permintaan. OK, mari kita masuk ke topik di sini.

  1. Skenario permintaan: Jadi apa jenis pekerjaan yang ingin kita lakukan? Sederhananya, kita memiliki banyak indikator, strategi, kode, dll yang dapat kita pilih untuk digunakan di TradingView, yang dapat dijalankan langsung di TradingView untuk menggambar garis, menghitung dan menampilkan sinyal perdagangan. Selain itu, TradingView memiliki data harga real-time dan data K-line yang cukup untuk memfasilitasi perhitungan berbagai indikator. Kode skrip ini di TradingView disebut bahasa PINE. Satu-satunya hal yang tidak nyaman adalah bahwa perdagangan bot nyata di TradingView. Meskipun bahasa PINE didukung di FMZ, itu juga dapat digunakan untuk perdagangan bot nyata. Namun, ada beberapa penggemar TradingView yang masih ingin menempatkan pesanan menggunakan sinyal dari grafik di TradingView, sehingga ini dapat diselesaikan oleh FMZ. Jadi dalam artikel ini, kita akan menjelaskan rincian solusi.

  2. Prinsipnya:

img

Ada empat subjek yang terlibat dalam seluruh skema, yang, secara singkat adalah sebagai berikut:

img

Jadi jika Anda ingin menggunakannya dengan cara ini, Anda perlu persiapan ini:

  1. Skrip yang berjalan di TradingView bertanggung jawab untuk mengirim permintaan sinyal ke antarmuka API diperluas FMZ. Akun TradingView harus menjadi anggota PRO setidaknya.
  2. Untuk menyebarkan program docker di FMZ, itu perlu jenis yang dapat mengakses antarmuka pertukaran (seperti server di Singapura, Jepang, Hong Kong, dll).
  3. Mengkonfigurasi API KEY dari pertukaran untuk (menempatkan pesanan) operasi ketika sinyal TradingView dikirim di FMZ.
  4. Anda perlu memiliki Strategi Eksekusi Sinyal TradingView, yang terutama dibahas dalam artikel ini.

Strategi Eksekusi Sinyal TradingView

Desain TradingView Signal Execution Strategy dalam versi sebelumnya tidak terlalu fleksibel. Pesan hanya dapat ditulis ke url permintaan yang dikirim oleh TradingView. Jika kita ingin TradingView menulis beberapa informasi variabel di Body saat mendorong pesan, kita tidak dapat melakukan apa pun saat ini. Misalnya, konten pesan seperti pada TradingView:

img

Kemudian TradingView dapat diatur seperti yang ditunjukkan dalam gambar untuk menulis pesan di request Body dan mengirimkannya ke antarmuka API diperpanjang FMZ. Bagaimana untuk memanggil antarmuka API diperpanjang FMZ?

Dalam serangkaian antarmuka API diperpanjang FMZ, kita perlu menggunakanCommandRobotinterface, yang biasanya disebut sebagai berikut:

https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[186515,"ok12345"]

Peraturanaccess_keydansecret_keydalamquerydari url permintaan ini adalah yang diperpanjangAPI KEYdari platform FMZ, di sini demo diatur untukxxxdanyyyy. Lalu bagaimana membuat kunci ini? Di halaman ini:https://www.fmz.com/m/account, membuat di atasnya, menyimpannya dengan benar, tidak mengungkapkan itu.

img

Kembali ke titik, mari kita lanjutkan berbicara tentang masalah antarmuka dariCommandRobot. Jika Anda perlu mengaksesCommandRobotantarmukamethoddalam permintaan akan ditetapkan untuk:CommandRobot. Fungsi dariCommandRobotantarmuka adalah untuk mengirim pesan interaktif ke bot nyata dengan ID melalui platform FMZ, sehingga parameterargsberisi ID bot yang sebenarnya dan pesan. contoh url permintaan di atas adalah untuk mengirim pesanok12345ke program bot nyata dengan ID 186515.

Sebelumnya, metode ini digunakan untuk meminta antarmuka CommandRobot dari FMZ diperluas API.ok12345. Jika pesan berada di Badan yang diminta, Anda perlu menggunakan metode lain:

https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[130350,+""]

Dengan cara ini permintaan dapat mengirim isi dari Badan dalam permintaan sebagai pesan interaktif ke bot nyata dengan ID130350melalui platform FMZ. Jika pesan pada TradingView diatur untuk:{"close": {{close}}, "name": "aaa"}, maka bot asli dengan ID dari130350akan menerima instruksi interaktif:{"close": 39773.75, "name": "aaa"}

Agar Strategi Eksekusi Sinyal TradingView dapat memahami perintah yang dikirim oleh TradingView saat menerima perintah interaktif, format pesan berikut harus disepakati sebelumnya:

{
    Flag: "45M103Buy",     // Marker, which can be specified at will
    Exchange: 1,           // Specify exchange trading pairs
    Currency: "BTC_USDT",  // Trading pair
    ContractType: "swap",  // Contract type, swap, quarter, next_quarter, fill in spot for spot
    Price: "{{close}}",    // Opening position or closing position price, -1 is the market price
    Action: "buy",         // Transaction type [buy: spot buying, sell: spot selling, long: go long futures, short: go short futures, closesell: buy futures and close short positions, close buy: sell futures and close long positions]
    Amount: "0",           // Transaction amount
}

Strategi ini dirancang sebagai arsitektur multi-exchange, sehingga beberapa objek pertukaran dapat dikonfigurasi pada strategi ini, yaitu, operasi penempatan pesanan dari beberapa akun yang berbeda dapat dikendalikan. Hanya Exchange dalam struktur sinyal yang menentukan pertukaran yang akan dioperasikan. Pengaturan 1 adalah untuk memungkinkan sinyal ini untuk mengoperasikan akun pertukaran yang sesuai dengan objek pertukaran pertama yang ditambahkan. Jika spot ContractType diatur ke spot, futures akan menulis kontrak tertentu, seperti, swap untuk kontrak abadi. Daftar harga pasar dapat dilewatkan di -1. Pengaturan tindakan berbeda untuk futures, spot, posisi pembukaan dan penutupan, dan tidak dapat ditetapkan dengan salah.

Selanjutnya, Anda dapat merancang kode strategi. kode strategi lengkap:

//Signal structure
var Template = {
    Flag: "45M103Buy",     // Marker, which can be specified at will
    Exchange: 1,           // Specify exchange trading pairs
    Currency: "BTC_USDT",  // Trading pair
    ContractType: "swap",  // Contract type, swap, quarter, next_quarter, fill in spot for spot
    Price: "{{close}}",    // Opening position or closing position price, -1 is the market price
    Action: "buy",         // Transaction type [buy: spot buying, sell: spot selling, long: go long futures, short: go short futures, closesell: buy futures and close short positions, close buy: sell futures and close long positions]
    Amount: "0",           // Transaction amount
}

var BaseUrl = "https://www.fmz.com/api/v1"   // FMZ extended API interface address
var RobotId = _G()                           // Current real bot ID
var Success = "#5cb85c"    // Color for success
var Danger = "#ff0000"     // Color for danger
var Warning = "#f0ad4e"    // Color for alert
var buffSignal = []

// Check signal message format
function DiffObject(object1, object2) {
    const keys1 = Object.keys(object1)
    const keys2 = Object.keys(object2)
    if (keys1.length !== keys2.length) {
        return false
    }
    for (let i = 0; i < keys1.length; i++) {
        if (keys1[i] !== keys2[i]) {
            return false
        }
    }
    return true
}

function CheckSignal(Signal) {
    Signal.Price = parseFloat(Signal.Price)
    Signal.Amount = parseFloat(Signal.Amount)
    if (Signal.Exchange <= 0 || !Number.isInteger(Signal.Exchange)) {
        Log("The minimum number of the exchange is 1 and it is an integer", Danger)
        return
    }
    if (Signal.Amount <= 0 || typeof(Signal.Amount) != "number") {
        Log("The transaction amount cannot be less than 0 and it is numerical type", typeof(Signal.Amount), Danger)
        return
    }
    if (typeof(Signal.Price) != "number") {
        Log("Price must be a value", Danger)
        return
    }
    if (Signal.ContractType == "spot" && Signal.Action != "buy" && Signal.Action != "sell") {
        Log("The command is to operate spot, Action error, Action:", Signal.Action, Danger)
        return 
    }
    if (Signal.ContractType != "spot" && Signal.Action != "long" && Signal.Action != "short" && Signal.Action != "closesell" && Signal.Action != "closebuy") {
        Log("The command is to operate future, Action error, Action:", Signal.Action, Danger)
        return 
    }
    return true
}

function commandRobot(url, accessKey, secretKey, robotId, cmd) {
    // https://www.fmz.com/api/v1?access_key=xxx&secret_key=xxx&method=CommandRobot&args=[xxx,+""]
    url = url + '?access_key=' + accessKey + '&secret_key=' + secretKey + '&method=CommandRobot&args=[' + robotId + ',+""]'
    var postData = {
        method:'POST', 
        data:cmd
    }
    var headers = "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36\nContent-Type: application/json"
    var ret = HttpQuery(url, postData, "", headers)
    Log("Simulate a webhook request from TradingView, sending a POST request for testing purposes:", url, "body:", cmd, "response:", ret)
}

function createManager() {
    var self = {}
    self.tasks = []
    
    self.process = function() {
        var processed = 0
        if (self.tasks.length > 0) {
            _.each(self.tasks, function(task) {
                if (!task.finished) {
                    processed++
                    self.pollTask(task)
                }
            })
            if (processed == 0) {
                self.tasks = []
            }
        }
    }
    
    self.newTask = function(signal) {
        // {"Flag":"45M103Buy","Exchange":1,"Currency":"BTC_USDT","ContractType":"swap","Price":"10000","Action":"buy","Amount":"0"}
        var task = {}
        task.Flag = signal["Flag"]
        task.Exchange = signal["Exchange"]
        task.Currency = signal["Currency"]
        task.ContractType = signal["ContractType"]
        task.Price = signal["Price"]
        task.Action = signal["Action"]
        task.Amount = signal["Amount"]
        task.exchangeIdx = signal["Exchange"] - 1
        task.pricePrecision = null
        task.amountPrecision = null 
        task.error = null 
        task.exchangeLabel = exchanges[task.exchangeIdx].GetLabel()
        task.finished = false 
        
        Log("Create task:", task)
        self.tasks.push(task)
    }
    
    self.getPrecision = function(n) {
        var precision = null 
        var arr = n.toString().split(".")
        if (arr.length == 1) {
            precision = 0
        } else if (arr.length == 2) {
            precision = arr[1].length
        } 
        return precision
    }
    
    self.pollTask = function(task) {
        var e = exchanges[task.exchangeIdx]
        var name = e.GetName()
        var isFutures = true
        e.SetCurrency(task.Currency)
        if (task.ContractType != "spot" && name.indexOf("Futures_") != -1) {
            // Non-spot, then set the contract
            e.SetContractType(task.ContractType)
        } else if (task.ContractType == "spot" && name.indexOf("Futures_") == -1) {
            isFutures = false 
        } else {
            task.error = "The ContractType in the command does not match the configured exchange object type"
            return 
        }
        
        var depth = e.GetDepth()
        if (!depth || !depth.Bids || !depth.Asks) {
            task.error = "Order book data exception"
            return 
        }
        
        if (depth.Bids.length == 0 && depth.Asks.length == 0) {
            task.error = "No orders on the market entry position"
            return 
        }
        
        _.each([depth.Bids, depth.Asks], function(arr) {
            _.each(arr, function(order) {
                var pricePrecision = self.getPrecision(order.Price)
                var amountPrecision = self.getPrecision(order.Amount)
                if (Number.isInteger(pricePrecision) && !Number.isInteger(self.pricePrecision)) {
                    self.pricePrecision = pricePrecision
                } else if (Number.isInteger(self.pricePrecision) && Number.isInteger(pricePrecision) && pricePrecision > self.pricePrecision) {
                    self.pricePrecision = pricePrecision
                }
                if (Number.isInteger(amountPrecision) && !Number.isInteger(self.amountPrecision)) {
                    self.amountPrecision = amountPrecision
                } else if (Number.isInteger(self.amountPrecision) && Number.isInteger(amountPrecision) && amountPrecision > self.amountPrecision) {
                    self.amountPrecision = amountPrecision
                }
            })
        })

        if (!Number.isInteger(self.pricePrecision) || !Number.isInteger(self.amountPrecision)) {
            task.err = "Failed to obtain precision"
            return 
        }
        
        e.SetPrecision(self.pricePrecision, self.amountPrecision)
        
        // buy: spot buying, sell: spot selling, long: go long futures, short: go short futures, closesell: buy futures and close short positions, close buy: sell futures and close long positions
        var direction = null 
        var tradeFunc = null 
        if (isFutures) {
            switch (task.Action) {
                case "long": 
                    direction = "buy"
                    tradeFunc = e.Buy 
                    break
                case "short": 
                    direction = "sell"
                    tradeFunc = e.Sell
                    break
                case "closesell": 
                    direction = "closesell"
                    tradeFunc = e.Buy 
                    break
                case "closebuy": 
                    direction = "closebuy"
                    tradeFunc = e.Sell
                    break
            }
            if (!direction || !tradeFunc) {
                task.error = "Wrong transaction direction:" + task.Action
                return 
            }
            e.SetDirection(direction)
        } else {
            if (task.Action == "buy") {
                tradeFunc = e.Buy 
            } else if (task.Action == "sell") {
                tradeFunc = e.Sell 
            } else {
                task.error = "Wrong transaction direction:" + task.Action
                return 
            }
        }
        var id = tradeFunc(task.Price, task.Amount)
        if (!id) {
            task.error = "Failed to place an order"
        }
        
        task.finished = true
    }
    
    return self
}

var manager = createManager()
function HandleCommand(signal) {
    // Detect whether interactive command is received
    if (signal) {
        Log("Receive interactive command:", signal)     // Receive the interactive command, print the interactive command
    } else {
        return                            // If it is not received, it will be returned directly without processing
    }
    
    // Check whether the interactive command is a test instruction. The test instruction can be sent out by the current strategy interaction control for testing
    if (signal.indexOf("TestSignal") != -1) {
        signal = signal.replace("TestSignal:", "")
        // Call the FMZ extended API interface to simulate the webhook of the TradingView, and the message sent by the interactive button TestSignal: {"Flag":"45M103Buy","Exchange":1,"Currency":"BTC_USDT","ContractType":"swap","Price":"10000","Action":"buy","Amount":"0"}
        commandRobot(BaseUrl, FMZ_AccessKey, FMZ_SecretKey, RobotId, signal)
    } else if (signal.indexOf("evalCode") != -1) {
        var js = signal.split(':', 2)[1]
        Log("Execute debug code:", js)
        eval(js)
    } else {
        // Process signal command
        objSignal = JSON.parse(signal)
        if (DiffObject(Template, objSignal)) {
            Log("Received transaction signal command:", objSignal)
            buffSignal.push(objSignal)
            
            // Check the trading volume and exchange number
            if (!CheckSignal(objSignal)) {
                return
            }
            
            // Create task
            manager.newTask(objSignal)
        } else {
            Log("Command cannot be recognized", signal)
        }
    }
}

function main() {
    Log("WebHook address:", "https://www.fmz.com/api/v1?access_key=" + FMZ_AccessKey + "&secret_key=" + FMZ_SecretKey + "&method=CommandRobot&args=[" + RobotId + ',+""]', Danger)
    Log("Transaction type [buy: spot buying, sell: spot selling, long: go long futures, short: go short futures, closesell: buy futures and close short positions, close buy: sell futures and close long positions]", Danger)
    Log("Command template:", JSON.stringify(Template), Danger)
    
    while (true) {
        try {
            // Process interactions
            HandleCommand(GetCommand())
            
            // Process tasks
            manager.process()
            
            if (buffSignal.length > maxBuffSignalRowDisplay) {
                buffSignal.shift()
            }
            var buffSignalTbl = {
                "type" : "table",
                "title" : "Signal recording",
                "cols" : ["Flag", "Exchange", "Currency", "ContractType", "Price", "Action", "Amount"],
                "rows" : []
            }
            for (var i = buffSignal.length - 1 ; i >= 0 ; i--) {
                buffSignalTbl.rows.push([buffSignal[i].Flag, buffSignal[i].Exchange, buffSignal[i].Currency, buffSignal[i].ContractType, buffSignal[i].Price, buffSignal[i].Action, buffSignal[i].Amount])
            }
            LogStatus(_D(), "\n", "`" + JSON.stringify(buffSignalTbl) + "`")
            Sleep(1000 * SleepInterval)
        } catch (error) {
            Log("e.name:", error.name, "e.stack:", error.stack, "e.message:", error.message)
            Sleep(1000 * 10)
        }
    }
}

Parameter dan interaksi strategi:

img

Alamat strategi lengkap dari Trading View Signal Execution Strategy:https://www.fmz.com/strategy/392048

Tes sederhana

Sebelum menjalankan strategi, objek pertukaran harus dikonfigurasi, dan dua parameter AccessKey on FMZ Platform dan SecretKey on FMZ Platform harus ditetapkan dalam parameter strategi.

img

Ini akan mencetak alamat WebHook, didukung perintah tindakan, dan format pesan yang perlu diisi di TradingView.

https://www.fmz.com/api/v1?access_key=22903bab96b26584dc5a22522984df42&secret_key=73f8ba01014023117cbd30cb9d849bfc&method=CommandRobot&args=[505628,+""]

Hanya menyalin dan menempelkannya langsung ke lokasi yang sesuai di TradingView.

Jika Anda ingin mensimulasikan sinyal yang dikirim oleh TradingView, Anda dapat mengklik tombol TestSignal pada interaksi strategi.

img

Strategi ini mengirim permintaan sendiri (mensimulasikan TradingView mengirim permintaan sinyal), memanggil antarmuka API diperluas FMZ untuk mengirim pesan ke strategi itu sendiri:

{"Flag":"45M103Buy","Exchange":1,"Currency":"BTC_USDT","ContractType":"swap","Price":"16000","Action":"buy","Amount":"1"}

Strategi saat ini akan menerima pesan interaktif lain dan melaksanakan, dan menempatkan pesanan untuk transaksi.

Pengujian penggunaan TradingView dalam adegan yang sebenarnya

Menggunakan tes TradingView mengharuskan akun TradingView berada pada tingkat Pro. Sebelum tes, Anda perlu mengetahui beberapa pengetahuan sebelumnya.

Ambil skrip PINE sederhana (secara acak ditemukan dan dimodifikasi di TradingView) sebagai contoh

//@version=5
strategy("Consecutive Up/Down Strategy", overlay=true)
consecutiveBarsUp = input(3)
consecutiveBarsDown = input(3)
price = close
ups = 0.0
ups := price > price[1] ? nz(ups[1]) + 1 : 0
dns = 0.0
dns := price < price[1] ? nz(dns[1]) + 1 : 0
if (not barstate.ishistory and ups >= consecutiveBarsUp and strategy.position_size <= 0)
    action = strategy.position_size < 0 ? "closesell" : "long"
    strategy.order("ConsUpLE", strategy.long, 1, comment=action)
if (not barstate.ishistory and dns >= consecutiveBarsDown and strategy.position_size >= 0)
    action = strategy.position_size > 0 ? "closebuy" : "short"
    strategy.order("ConsDnSE", strategy.short, 1, comment=action)
  1. Skrip PINE dapat melampirkan beberapa informasi ketika skrip mengirim perintah instruksi

Berikut ini adalah placeholder.{{strategy.order.contracts}}dalam kotak message dari peringatan, pesan akan dikirim ketika perintah dipicu (sesuai dengan pengaturan pada peringatan, push mail, permintaan url webhook, pop-up, dll.), Dan pesan akan berisi jumlah perintah yang dilaksanakan saat ini.

{{strategy.position_size}}- Mengembalikan nilai kata kunci yang sama di Pine, yaitu ukuran posisi saat ini.{{strategy.order.action}}- Kembali string buy atau sell untuk perintah yang dieksekusi.{{strategy.order.contracts}}- Mengembalikan jumlah kontrak yang telah dieksekusi{{strategy.order.price}}- Kembalikan harga perintah yang dilaksanakan.{{strategy.order.id}}- Mengembalikan ID perintah yang dieksekusi (string yang digunakan sebagai parameter pertama dalam salah satu panggilan fungsi yang menghasilkan perintah: strategi.entry,strategy.exitatau strategi.order).{{strategy.order.comment}}- Mengembalikan komentar dari perintah yang dieksekusi (string yang digunakan dalam parameter komentar dalam salah satu panggilan fungsi yang menghasilkan perintah: strategi.entry,strategy.exitJika tidak ada komentar yang ditentukan, nilai daristrategy.order.idakan digunakan.{{strategy.order.alert_message}}- Mengembalikan nilai parameter alert_message yang dapat digunakan dalam kode strategis Pine ketika memanggil salah satu fungsi yang digunakan untuk menempatkan pesanan: strategi.entry,strategy.exit, atau strategi.order. Ini hanya didukung di Pine v4.{{strategy.market_position}}- Kembalikan posisi strategi saat ini sebagai string: long, flat, atau short.{{strategy.market_position_size}}- Mengembalikan ukuran posisi saat ini dalam bentuk nilai absolut (yaitu, angka non-negatif).{{strategy.prev_market_position}}- Kembali posisi sebelumnya dari strategi sebagai string: long, flat, atau short.{{strategy.prev_market_position_size}}- Mengembalikan ukuran posisi sebelumnya dalam bentuk nilai absolut (yaitu, bilangan non-negatif).

  1. Membangun pesan dalam kombinasi dengan Strategi Eksekusi Sinyal TradingView
{
    "Flag":"{{strategy.order.id}}",
    "Exchange":1,
    "Currency":"BTC_USDT",
    "ContractType":"swap",
    "Price":"-1",
    "Action":"{{strategy.order.comment}}",
    "Amount":"{{strategy.order.contracts}}"
}
  1. Biarkan TradingView mengirim sinyal sesuai dengan menjalankan skrip PINE. Anda perlu mengatur peringatan saat memuat skrip pada TradingView

Ketika skrip PINE pada TradingView memicu transaksi, permintaan url webhook akan dikirim.

img

Robot FMZ yang sebenarnya akan mengeksekusi sinyal ini.

img

Kode dalam artikel ini hanya untuk referensi, dan dapat disesuaikan dan diperluas oleh Anda sendiri dalam penggunaan yang sebenarnya.


Berkaitan

Lebih banyak