Satu lagi Skim Strategi Pelaksanaan Isyarat TradingView

Penulis:Lydia, Dicipta: 2022-12-15 21:23:24, Dikemas kini: 2023-09-18 20:01:55

img

Satu lagi Skim Strategi Pelaksanaan Isyarat TradingView

Pedagang yang sering menggunakan TradingView tahu bahawa TradingView boleh mendorong mesej ke platform lain. Dalam Digest platform FMZ kami, terdapat strategi push isyarat TradingView yang diterbitkan di perpustakaan, di mana kandungan mesej yang didorong ditulis dalam url permintaan, yang agak tidak fleksibel.

Skenario dan Prinsip

Beberapa pemula mungkin keliru dengan tajuk artikel ini dan penerangan di atas, tidak kira! Mari kita mulakan dengan penerangan yang jelas tentang senario dan prinsip permintaan.

  1. Senario permintaan: Jadi apa jenis kerja yang kita mahu ia lakukan? Secara ringkasnya, kita mempunyai banyak penunjuk, strategi, kod, dan lain-lain yang boleh kita pilih untuk digunakan di TradingView, yang boleh dijalankan secara langsung di TradingView untuk menarik garis, mengira dan memaparkan isyarat perdagangan. Di samping itu, TradingView mempunyai data harga masa nyata dan data K-line yang mencukupi untuk memudahkan pengiraan pelbagai indikator. Kod skrip ini di TradingView dipanggil bahasa PINE. Satu-satunya perkara yang tidak mudah adalah bahawa bot sebenar berdagang di TradingView. Walaupun bahasa PINE disokong di FMZ, ia juga boleh digunakan untuk perdagangan bot sebenar. Walau bagaimanapun, terdapat beberapa peminat TradingView yang masih mahu meletakkan pesanan menggunakan isyarat dari carta di TradingView, jadi ini boleh diselesaikan oleh FMZ. Jadi dalam artikel ini, kita akan menerangkan butiran penyelesaian.

  2. Prinsip:

img

Terdapat 4 subjek yang terlibat dalam keseluruhan skim, yang, secara ringkasnya adalah sebagai berikut:

img

Jadi jika anda mahu menggunakannya dengan cara ini, anda memerlukan persiapan ini:

  1. Skrip yang berjalan di TradingView bertanggungjawab untuk menghantar permintaan isyarat ke antara muka API lanjutan FMZ. Akaun TradingView mestilah sekurang-kurangnya ahli PRO.
  2. Untuk menyebarkan program docker di FMZ, ia perlu jenis yang boleh mengakses antara muka pertukaran (seperti pelayan di Singapura, Jepun, Hong Kong, dan lain-lain).
  3. Mengkonfigurasi API KEY pertukaran untuk (menempatkan pesanan) operasi apabila isyarat TradingView dihantar di FMZ.
  4. Anda perlu mempunyai Strategi Pelaksanaan Isyarat TradingView, yang terutama dibincangkan dalam artikel ini.

Strategi Pelaksanaan Isyarat TradingView

Reka bentuk Strategi Pelaksanaan Isyarat TradingView dalam versi terdahulu tidak begitu fleksibel. Mesej hanya boleh ditulis ke url permintaan yang dihantar oleh TradingView. Jika kita mahu TradingView menulis beberapa maklumat pembolehubah di badan ketika mendorong mesej, kita tidak boleh melakukan apa-apa pada masa ini. Sebagai contoh, kandungan mesej seperti di TradingView:

img

Kemudian TradingView boleh ditetapkan seperti yang ditunjukkan dalam gambar untuk menulis mesej dalam badan permintaan dan menghantarnya ke antara muka API lanjutan FMZ. Bagaimana untuk memanggil antara muka API lanjutan FMZ?

Dalam satu siri sambungan API lanjutan FMZ, kita perlu menggunakanCommandRobotantara muka, yang biasanya dipanggil sebagai berikut:

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

Peraturanaccess_keydansecret_keydalamqueryUrl permintaan ini adalah URL yang diperluaskanAPI KEYdari platform FMZ, di sini demo ditetapkan untukxxxdanyyyy. Kemudian bagaimana untuk membuat kunci ini? Dalam halaman ini:https://www.fmz.com/m/account, buat di atasnya, simpan dengan betul, jangan mendedahkannya.

img

Kembali ke titik, mari kita terus bercakap tentang masalah antara mukaCommandRobot. Jika anda perlu mengaksesCommandRobotantara muka,methoddalam permintaan akan ditetapkan kepada:CommandRobot. FungsiCommandRobotantara muka adalah untuk menghantar mesej interaktif kepada bot sebenar dengan ID melalui platform FMZ, jadi parameterargsmengandungi ID bot sebenar dan mesej. contoh url permintaan di atas adalah untuk menghantar mesejok12345kepada program bot sebenar dengan ID 186515.

Sebelum ini, kaedah ini digunakan untuk meminta antara muka CommandRobot dari FMZ diperluaskan API.ok12345. Jika mesej adalah dalam Badan yang diminta, anda perlu menggunakan kaedah lain:

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

Dengan cara ini permintaan boleh menghantar kandungan badan dalam permintaan sebagai mesej interaktif kepada bot sebenar dengan ID130350melalui platform FMZ. Jika mesej pada TradingView ditetapkan untuk:{"close": {{close}}, "name": "aaa"}, maka bot sebenar dengan ID130350akan menerima arahan interaktif:{"close": 39773.75, "name": "aaa"}

Untuk Strategi Pelaksanaan Isyarat TradingView memahami arahan yang dihantar oleh TradingView dengan betul apabila menerima arahan interaktif, format mesej berikut harus dipersetujui terlebih dahulu:

{
    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 direka sebagai seni bina pelbagai pertukaran, jadi pelbagai objek pertukaran boleh dikonfigurasikan pada strategi ini, iaitu operasi penempatan pesanan beberapa akaun yang berbeza boleh dikawal. Hanya Bursa dalam struktur isyarat yang menentukan pertukaran yang akan dikendalikan. Tetapan 1 adalah untuk membolehkan isyarat ini mengendalikan akaun pertukaran yang sepadan dengan objek pertukaran pertama yang ditambahkan. Jika Spot ContractType ditetapkan untuk spot, niaga hadapan akan menulis kontrak tertentu, seperti swap untuk kontrak kekal. Senarai harga pasaran boleh lulus dalam -1. Tetapan tindakan berbeza untuk niaga hadapan, spot, pembukaan dan penutupan kedudukan, dan ia tidak boleh ditetapkan dengan salah.

Seterusnya, anda boleh merancang kod strategi.

//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 strategi dan interaksi:

img

Alamat strategi lengkap Strategi Pelaksanaan Isyarat Lihat Perdagangan:https://www.fmz.com/strategy/392048

Ujian mudah

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

img

Ia akan mencetak alamat WebHook, sokongan perintah Tindakan, dan format mesej yang perlu diisi dalam TradingView.

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

Hanya salin dan tampal terus ke lokasi yang sepadan di TradingView.

Jika anda ingin mensimulasikan isyarat yang dihantar oleh TradingView, anda boleh klik pada butang TestSignal pada interaksi strategi.

img

Strategi ini menghantar permintaan sendiri (meniru TradingView yang menghantar permintaan isyarat), memanggil antara muka API lanjutan FMZ untuk menghantar mesej ke strategi itu sendiri:

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

Strategi semasa akan menerima mesej interaktif lain dan melaksanakan, dan meletakkan pesanan untuk transaksi.

Ujian menggunakan TradingView dalam adegan sebenar

Menggunakan ujian TradingView memerlukan bahawa akaun TradingView adalah pada tahap Pro.

Ambil skrip PINE mudah (secara rawak dijumpai dan diubah suai pada 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 boleh melampirkan beberapa maklumat apabila skrip menghantar arahan perintah

Berikut adalah tempat penahan. Contohnya, jika saya menulis{{strategy.order.contracts}}dalam kotak message amaran, mesej akan dihantar apabila perintah itu dicetuskan (mengikut tetapan pada amaran, pos dorong, permintaan url webhook, pop-up, dll.), dan mesej akan mengandungi bilangan perintah yang dilaksanakan pada masa ini.

{{strategy.position_size}}- Kembalikan nilai kata kunci yang sama dalam Pine, iaitu saiz kedudukan semasa.{{strategy.order.action}}- Kembalikan rentetan buy atau sell untuk perintah yang dilaksanakan.{{strategy.order.contracts}}- Kembalikan jumlah kontrak yang telah dilaksanakan.{{strategy.order.price}}- Kembalikan harga perintah yang dilaksanakan.{{strategy.order.id}}- Kembalikan ID perintah yang dilaksanakan (string yang digunakan sebagai parameter pertama dalam salah satu panggilan fungsi yang menjana perintah: strategi.entry,strategy.exitatau strategi.order).{{strategy.order.comment}}- Kembali komen perintah yang dilaksanakan (string yang digunakan dalam parameter komen dalam salah satu panggilan fungsi yang menjana perintah: strategi.entry,strategy.exit, atau strategi.order). Jika tiada komen ditentukan, nilaistrategy.order.idakan digunakan.{{strategy.order.alert_message}}- Kembalikan nilai parameter alert_message yang boleh digunakan dalam kod strategis Pine apabila memanggil salah satu fungsi yang digunakan untuk meletakkan pesanan: strategi.entry,strategy.exit, atau strategi.order. Ini hanya disokong dalam Pine v4.{{strategy.market_position}}- Kembalikan kedudukan semasa strategi sebagai rentetan: long, flat, atau short.{{strategy.market_position_size}}- Mengembalikan saiz kedudukan semasa dalam bentuk nilai mutlak (iaitu, nombor bukan negatif).{{strategy.prev_market_position}}- Kembalikan kedudukan strategi sebelumnya sebagai rentetan: panjang, datar, atau pendek.{{strategy.prev_market_position_size}}- Mengembalikan saiz kedudukan sebelumnya dalam bentuk nilai mutlak (iaitu, nombor bukan negatif).

  1. Membina mesej dalam kombinasi dengan Strategi Pelaksanaan Isyarat TradingView
{
    "Flag":"{{strategy.order.id}}",
    "Exchange":1,
    "Currency":"BTC_USDT",
    "ContractType":"swap",
    "Price":"-1",
    "Action":"{{strategy.order.comment}}",
    "Amount":"{{strategy.order.contracts}}"
}
  1. Biar TradingView menghantar isyarat mengikut menjalankan skrip PINE.

Apabila skrip PINE pada TradingView mencetuskan transaksi, permintaan url webhook akan dihantar.

img

Robot FMZ sebenar akan melaksanakan isyarat ini.

img

Kod dalam artikel ini adalah untuk rujukan sahaja, dan ia boleh diselaraskan dan diperluaskan oleh anda sendiri dalam penggunaan sebenar.


Berkaitan

Lebih lanjut