別のTradingViewシグナル実行戦略計画

作者: リン・ハーンリディア, 作成日:2022-12-15 21:23:24, 更新日:2023-09-18 20:01:55

img

別のTradingViewシグナル実行戦略計画

TradingViewを頻繁に使用するトレーダーは,TradingViewがメッセージを他のプラットフォームにプッシュできることを知っています. FMZプラットフォームのDigestでは,ライブラリに公開されたTradingView信号プッシュ戦略があり,プッシュされたメッセージの内容はリクエストURLに書かれていました.これはかなり柔軟ではありません.この記事では,新しい方法でTradingView信号実行戦略を再設計します.

シナリオ と 原則

この記事のタイトルと上記の説明は,初心者にとって混乱を招くかもしれません.それは問題ではありません! 需要シナリオと原則の明確な説明から始めましょう.OK,ここで話題に入ります.

  1. 需要シナリオ: では,どのような仕事をしたいのでしょうか? 簡単に言うと,TradingViewで選択できる多くのインジケーター,戦略,コードなどがあります. これらのインジケーターは,直接TradingViewで実行してラインを描き,計算し,取引シグナルを表示することができます. さらに,TradingViewにはリアルタイム価格データと,さまざまなインジケーターの計算を容易にするのに十分なKラインデータがあります. TradingView上のこれらのスクリプトコードはPINE言語と呼ばれます.唯一便利でないのは,TradingView上の実際のボット取引です.PINE言語はFMZでサポートされているものの,実際のボット取引にも使用できます.しかし,TradingView上のチャートからのシグナルを使用して注文をしたいTradingViewのファンがまだいくつかいるので,これはFMZで解決できます.この記事では,解決策の詳細を説明します.

  2. 原則:

img

計画全体には4つのテーマが関わっています. 概要は以下の通りです.

img

薬の使い方はこうです

  1. TradingViewで実行されるスクリプトは,FMZの拡張 API インターフェースに信号要求を送信する責任を負います. TradingView アカウントは少なくとも PRO メンバーでなければなりません.
  2. FMZにドッカープログラムを展開するには,交換インターフェース (シンガポール,日本,香港などのサーバーなど) にアクセスできるタイプである必要があります.
  3. 取引所の API KEY を FMZ で TradingView シグナルが送信されたときに (注文を出す) 操作するように設定する.
  4. この記事では主に議論される TradingView Signal Execution Strategyが必要です.

トレーディングView 信号実行戦略

前のバージョンの"TradingView Signal Execution Strategy"のデザインは柔軟ではありません.メッセージは,TradingViewから送信された要求のURLにのみ書き込むことができます.メッセージをプッシュする際にTradingViewがボディにいくつかの変数情報を書き込むことを望む場合は,現時点では何もできません.例えば,TradingView上のメッセージのコンテンツは:

img

要求ボディにメッセージを書いて FMZ の拡張 API インターフェースに送信する TradeView を設定できます. FMZ の拡張 API インターフェースを呼び出すにはどうすればよいですか?

FMZの拡張 API インターフェースのシリーズでは,我々は使用する必要がありますCommandRobotインターフェースは通常,以下のように呼ばれます.

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

についてaccess_keyそしてsecret_keyについてqueryこのリクエストのURLは拡張されています.API KEY試行錯誤を表示します.xxxそしてyyyyこのページでは,この鍵を入力します.https://www.fmz.com/m/account作り出し 適切に保管し 公開しないでください

img

インタフェースの問題について話を続けましょう.CommandRobotサイトにアクセスしたい場合はCommandRobotインターフェース,method要求の設定は次のようになります.CommandRobot機能についてCommandRobotFMZプラットフォームを通じてIDを持つ本物のボットにインタラクティブなメッセージを送信します.args上記のリクエスト url の例は,メッセージを送信します.ok12345本物のボットプログラムに 186515のIDで

以前,この方法は FMZ 拡張 API の CommandRobot インターフェースをリクエストするために使用されていました. メッセージは上記の例でのみ記述できます.ok12345メッセージが要求されたボディにある場合は,別の方法を使用する必要があります:

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

インタラクティブなメッセージとして,IDを持つ実際のボットに送信することができます.130350FMZ プラットフォームを通してです.もし TradingView のメッセージが:{"close": {{close}}, "name": "aaa"}真のボットです130350インタラクティブな指示を受けます{"close": 39773.75, "name": "aaa"}

TradingView Signal Execution Strategyが,インタラクティブなコマンドを受信する際にTradingViewが送信するコマンドを正しく理解するために,次のメッセージ形式を事前に合意する必要があります.

{
    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
}

この戦略はマルチ交換アーキテクチャとして設計されているため,この戦略で複数の交換オブジェクトを構成することができる.つまり,複数の異なるアカウントのオーダー配置操作を制御することができる.シグナル構造内の交換のみが操作される交換を指定する.設定1は,この信号が最初の追加された交換オブジェクトに対応する交換アカウントを操作できるようにすることです.スポットコントラクトタイプがスポットに設定されている場合,先行は永久契約のスワップなどの特定の契約を書きます.市場価格リストは -1で通過できます.アクション設定は先行,スポット,開設および閉じるポジションには異なります.正しく設定することはできません.

次に戦略コードを設計します 戦略コードを完了します

//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)
        }
    }
}

戦略パラメータと相互作用

img

Trading View Signal Execution Strategyの完全な戦略アドレス:https://www.fmz.com/strategy/392048

簡単なテスト

戦略を実行する前に,交換オブジェクトを構成し,戦略パラメータに2つのパラメータ"FMZプラットフォーム上のAccessKey"と"FMZプラットフォーム上のSecretKey"を設定する必要があります.実行すると,以下のように表示されます:

img

WebHook アドレス,サポートされているアクション コマンド,および TradingView で記入する必要があるメッセージ形式を印刷します.重要なのは WebHook アドレスです:

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

トレーディングビューの対応位置に直接コピーして貼り付けます

トレーディングビューから送信された信号をシミュレートしたい場合は,戦略インタラクションのテストシグナルボタンをクリックできます.

img

この戦略は独自のリクエストを送信 (信号リクエストを送信するTradingViewをシミュレート) し,FMZの拡張APIインターフェースを呼び出し,戦略そのものにメッセージを送信します:

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

現在の戦略は別のインタラクティブなメッセージを受け取り,実行し,取引の注文をします.

実際のシーンでTradingViewを使用するテスト

TradingViewテストを使用するには,TradingViewアカウントがプロレベルにある必要があります. テストの前に,あなたはいくつかの事前知識が必要です.

簡単なPINEスクリプト (TradingViewでランダムに見つかって修正された) を例に

//@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. PINE スクリプトは,命令命令を送信するときにいくつかの情報を添付することができます

記号の位置記号は次のとおりです.{{strategy.order.contracts}}警告の"メッセージ"欄では,命令が起動するとメッセージが送信されます (警告の設定,メールプッシュ,ウェブフックURL要求,ポップアップなどに応じて),メッセージには,この時に実行された命令の数が含まれます.

{{strategy.position_size}}- パインで同じキーワードの値,つまり現在のポジションのサイズを返します.{{strategy.order.action}}- 実行されたオーダーのために buy または sell の文字列を返します.{{strategy.order.contracts}}- 命令が実行された契約の数を返します.{{strategy.order.price}}- 実行命令の価格を返してください.{{strategy.order.id}}- 実行命令のIDを返します (命令を生成する関数呼び出しの1つの最初のパラメータとして使用される文字列: strategy.entry,strategy.exitまたは戦略.オーダー).{{strategy.order.comment}}- 実行命令のコメントを返します (命令を生成する関数呼び出しの1つでコメントパラメータで使用された文字列: strategy.entry,strategy.exitコメントが指定されていない場合,strategy.order.id使用されます.{{strategy.order.alert_message}}- 命令を出すために使用される関数の一つを呼び出すときに,戦略のPineコードで使用できる alert_messageパラメータの値を返します: strategy.entry,strategy.exitこれはPine v4 でのみサポートされます.{{strategy.market_position}}- ストラテジーの現在の位置を文字列として返します: , ,または .{{strategy.market_position_size}}- 絶対値 (つまり,負でない数) の形式で現在のポジションのサイズを返します.{{strategy.prev_market_position}}- ストラテジーの前の位置を文字列として返します: , ,または .{{strategy.prev_market_position_size}}絶対値 (つまり,負でない数) の形式で前の位置のサイズを返します.

  1. TradingView シグナル実行戦略と組み合わせてメッセージを構築する
{
    "Flag":"{{strategy.order.id}}",
    "Exchange":1,
    "Currency":"BTC_USDT",
    "ContractType":"swap",
    "Price":"-1",
    "Action":"{{strategy.order.comment}}",
    "Amount":"{{strategy.order.contracts}}"
}
  1. TradingViewにシグナルを送信します.

TradingViewの PINE スクリプトがトランザクションを起動すると,webhook url リクエストが送信されます.

img

FMZの本物のロボットは この信号を実行します

img

この記事 の コード は 参考 に 向け られ て いる だけ で あり,実際 に 使用 する とき に 自分 で 調整 や 拡張 する こと が でき ます.


関連性

もっと