別のTradingView信号実行戦略

作者: リン・ハーン小さな夢, 作成日:2022-11-30 10:52:07, 更新日:2023-09-18 20:01:09

[TOC]

img

別のTradingView信号実行戦略

TradingViewを頻繁に使用しているトレーダーは,TradingViewが他のプラットフォームにメッセージを送信できることを知っています.以前,TradingViewのシグナルプッシュ戦略も文庫に公開されました.

舞台と原理

この記事のタイトルと説明は,新しい生徒が少し変だと思うかもしれません. 構いません. まず,需要のシナリオや原理について説明します.

需要のシナリオ: 簡単に言うと,TradingViewでは,指針,戦略,コードなどから選択できるものがたくさんあります. これらはすべてTradingViewで直接実行できます. 線を描く,計算する,取引信号を表示するなどです. また,TradingViewにはリアルタイム価格データがあり,多くのK線データがあり,様々な指標を計算するのに便利です.

2 原則:

img

プロジェクト全体では4つの主体が関与しており,簡単に言うと以下の4つの主体です.

番号 主人公 記述
1 トレーディングビュー (図中のTrading View) TradingViewでPINEスクリプトを実行し,FMZの拡張APIインターフェイスにアクセスする信号を発信します
2 FMZプラットフォーム (写真のFMZプラットフォーム (ウェブサイト)) 仮想ディスク管理,仮想ディスクページ上でインタラクティブ指令を送信する,または拡張APIインターフェースによりFMZプラットフォームがホストにインタラクティブ指令を送信する,仮想ディスクのポリシープログラム
3 管理者ソフトウェア上の実装機プログラム (図のFMZ strategy robot) TradingViewの信号実行戦略が実際に実行される手順
4 取引所 (図の exchange) 現場設定の取引所,托管者の現場プロセスは直接注文の要求を送信する取引所

このゲームは,ゲームがうまくいくようにするために,いくつかの準備が必要です. 1. TradingView上で実行されるスクリプトで,FMZの拡張APIインターフェイスに信号要求を送信する. 2. FMZに托管プログラムを展開するには,取引所のインターフェースにアクセスできるようなもの (例えばシンガポール,日本,香港などのサーバー) が必要です. 3. FMZで,TradingView信号が送信されたときに操作する取引所のAPI KEYを設定します. 4. "TradingViewの信号実行戦略"が必要であり,この戦略が本記事のテーマです.

TradingViewの信号実行戦略

過去のバージョンの"TradingView信号実行策略"はあまり柔軟性がなく,メッセージはTradingViewが送信した要求のURLにのみ書き込まれる.

img

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

FMZの拡張APIインターフェースでは,CommandRobotこのインターフェースは,通常,以下のように呼びます.

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

このURLはquery中身access_keyそしてsecret_key広めるためのFMZプラットフォームですAPI KEYこのデモンストレーションでは,xxxそしてyyyyこのページでは,KEYの作成方法について説明します.https://www.fmz.com/m/account投稿者: 藤井 恵美 投稿者: 藤井 恵美 投稿者: 藤井 恵美

img

返信する 続きを読むCommandRobotインタフェースの問題です.CommandRobotインタフェース,要求のmethodフォローしているユーザー:CommandRobotCommandRobotこのインターフェースの機能は,FMZプラットフォームを通じて,IDのディスクにインタラクティブなメッセージを送信することです.argsこのリクエストのURLの例は,IDを186515メッセージを送信するok12345

以前は,この方法で FMZ の拡張 API の CommandRobot インターフェースを要求していたが,メッセージは,上記の例のように,書き留めしかできない.ok12345メッセージがリクエストされたボディに載っている場合,別の方法が必要です.

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

このリクエストは,FMZプラットフォームを通じて,リクエスト内のボディのコンテンツを,IDにインタラクティブメッセージとして送信することができます.130350取引視野のメッセージが設定されている場合:{"close": {{close}}, "name": "aaa"}このIDは,130350ビデオのビデオは,ビデオのビデオのビデオのビデオで,ビデオのビデオのビデオで,ビデオのビデオで,ビデオのビデオで.{"close": 39773.75, "name": "aaa"}

"TradingViewの信号実行策"がインタラクティブ指令を受け取ったときに,TradingViewから送信された指令を正しく理解できるように,メッセージの形式を事前に合意する必要があります.

{
    Flag: "45M103Buy",     // 标识,可随意指定
    Exchange: 1,           // 指定交易所交易对
    Currency: "BTC_USDT",  // 交易对
    ContractType: "swap",  // 合约类型,swap,quarter,next_quarter,现货填写spot
    Price: "{{close}}",    // 开仓或者平仓价格,-1为市价
    Action: "buy",         // 交易类型[ buy:现货买入 , sell:现货卖出 , long:期货做多 , short:期货做空 , closesell:期货买入平空 , closebuy:期货卖出平多]
    Amount: "0",           // 交易量
}

ポリシーはマルチエクスチェンジアーキテクチャとして設計されているため,このポリシーは複数のエクスチェンジオブジェクトを配置できる.つまり,複数の異なるアカウントの下注操作を制御できる.ただし,シグナル構造の中でExchangeが指定する取引所を使用すると,設定1は,このシグナル操作が最初の追加された取引所オブジェクトに対応する取引所アカウントに設定される.現金契約型設定を操作すると,先物特定のスポット契約,例えば永続契約スワップなどを書きます.市場価格転送-1はできます.Action設定は,先物,現金,開場,平止のいずれも異なる設定であり,誤りはありません.

策略コードを設計するには,次の手順を踏む必要があります.

//信号结构
var Template = {
    Flag: "45M103Buy",     // 标识,可随意指定
    Exchange: 1,           // 指定交易所交易对
    Currency: "BTC_USDT",  // 交易对
    ContractType: "swap",  // 合约类型,swap,quarter,next_quarter,现货填写spot
    Price: "{{close}}",    // 开仓或者平仓价格,-1为市价
    Action: "buy",         // 交易类型[ buy:现货买入 , sell:现货卖出 , long:期货做多 , short:期货做空 , closesell:期货买入平空 , closebuy:期货卖出平多]
    Amount: "0",           // 交易量
}

var BaseUrl = "https://www.fmz.com/api/v1"   // FMZ扩展API接口地址 
var RobotId = _G()                           // 当前实盘ID
var Success = "#5cb85c"    // 成功颜色
var Danger = "#ff0000"     // 危险颜色
var Warning = "#f0ad4e"    // 警告颜色
var buffSignal = []

// 校验信号消息格式
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("交易所最小编号为1,并且为整数", Danger)
        return
    }
    if (Signal.Amount <= 0 || typeof(Signal.Amount) != "number") {
        Log("交易量不能小于0,并且为数值类型", typeof(Signal.Amount), Danger)
        return
    }
    if (typeof(Signal.Price) != "number") {
        Log("价格必须是数值", Danger)
        return
    }
    if (Signal.ContractType == "spot" && Signal.Action != "buy" && Signal.Action != "sell") {
        Log("指令为操作现货,Action错误,Action:", Signal.Action, Danger)
        return 
    }
    if (Signal.ContractType != "spot" && Signal.Action != "long" && Signal.Action != "short" && Signal.Action != "closesell" && Signal.Action != "closebuy") {
        Log("指令为操作期货,Action错误,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("模拟TradingView的webhook请求,发送用于测试的POST请求:", url, "body:", cmd, "应答:", 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("创建任务:", 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) {
            // 非现货,则设置合约
            e.SetContractType(task.ContractType)
        } else if (task.ContractType == "spot" && name.indexOf("Futures_") == -1) {
            isFutures = false 
        } else {
            task.error = "指令中的ContractType与配置的交易所对象类型不匹配"
            return 
        }
        
        var depth = e.GetDepth()
        if (!depth || !depth.Bids || !depth.Asks) {
            task.error = "订单薄数据异常"
            return 
        }
        
        if (depth.Bids.length == 0 && depth.Asks.length == 0) {
            task.error = "盘口无订单"
            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 = "获取精度失败"
            return 
        }
        
        e.SetPrecision(self.pricePrecision, self.amountPrecision)
        
        // buy:现货买入 , sell:现货卖出 , long:期货做多 , short:期货做空 , closesell:期货买入平空 , closebuy:期货卖出平多
        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 = "交易方向错误:" + 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 = "交易方向错误:" + task.Action
                return 
            }
        }
        var id = tradeFunc(task.Price, task.Amount)
        if (!id) {
            task.error = "下单失败"
        }
        
        task.finished = true
    }
    
    return self
}

var manager = createManager()
function HandleCommand(signal) {
    // 检测是否收到交互指令
    if (signal) {
        Log("收到交互指令:", signal)     // 收到交互指令,打印交互指令
    } else {
        return                            // 没有收到时直接返回,不做处理
    }
    
    // 检测交互指令是否是测试指令,测试指令可以由当前策略交互控件发出来进行测试
    if (signal.indexOf("TestSignal") != -1) {
        signal = signal.replace("TestSignal:", "")
        // 调用FMZ扩展API接口,模拟Trading View的webhook,交互按钮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("执行调试代码:", js)
        eval(js)
    } else {
        // 处理信号指令
        objSignal = JSON.parse(signal)
        if (DiffObject(Template, objSignal)) {
            Log("接收到交易信号指令:", objSignal)
            buffSignal.push(objSignal)
            
            // 检查交易量、交易所编号
            if (!CheckSignal(objSignal)) {
                return
            }
            
            // 创建任务
            manager.newTask(objSignal)
        } else {
            Log("指令无法识别", signal)
        }
    }
}

function main() {
    Log("WebHook地址:", "https://www.fmz.com/api/v1?access_key=" + FMZ_AccessKey + "&secret_key=" + FMZ_SecretKey + "&method=CommandRobot&args=[" + RobotId + ',+""]', Danger)
    Log("交易类型[ buy:现货买入 , sell:现货卖出 , long:期货做多 , short:期货做空 , closesell:期货买入平空 , closebuy:期货卖出平多]", Danger)
    Log("指令模板:", JSON.stringify(Template), Danger)
    
    while (true) {
        try {
            // 处理交互
            HandleCommand(GetCommand())
            
            // 处理任务
            manager.process()
            
            if (buffSignal.length > maxBuffSignalRowDisplay) {
                buffSignal.shift()
            }
            var buffSignalTbl = {
                "type" : "table",
                "title" : "信号记录",
                "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

"TradingViewのシグナル実行戦略"の完全な戦略アドレス:https://www.fmz.com/strategy/392048

簡単なテスト

ポリシーを実行する前に,取引所オブジェクトを配置するには,ポリシーパラメータに"FMZプラットフォームのAccessKey"と"FMZプラットフォームのSecretKey"の2つのパラメータを設定してください.

img

WebHookのアドレス,サポートされているAction命令,メッセージ形式. WebHookのアドレスが重要です:

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

直接コピーして貼り付けると,TradingViewの位置が表示されます.

トレーディングビューの送信信号をシミュレートするには,ポリシーインタラクションのTestSignalボタンをクリックしてください.

img

このポリシーは,FMZの拡張APIインターフェースを呼び出し,リクエスト (シグナルリクエストを送信するTradingView模擬) を送信し,ポリシーの自己にメッセージを送信します.

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

既存のポリシーが別のインタラクションメッセージを受け取り,実行します.

img

取引を申し込みました.

トレーディングビューの実用化テスト

トレーディングビューのテストには,プロレベルの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}}命令が起動するとメッセージが送信されます (アラーム設定,メール転送,Webhook url要求,ポップウィンドウなどによる) そのメッセージには,この注文の実行数が含まれます.

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

2",TradingViewの信号実行策"を組み合わせてメッセージを作成する

{
    "Flag":"{{strategy.order.id}}",
    "Exchange":1,
    "Currency":"BTC_USDT",
    "ContractType":"swap",
    "Price":"-1",
    "Action":"{{strategy.order.comment}}",
    "Amount":"{{strategy.order.contracts}}"
}

3. このPINEスクリプトを実行する際にTradingViewが信号を発する場合は,このスクリプトをTradingViewにロードするときにアラームを設定する必要があります.

img

取引の動作をTradingViewのPINEスクリプトが誘発すると,webhook url要求が送信されます.

img

img

FMZのリアルディスクは,この信号を実行します.

img

img

ビデオアドレス

の動画:https://www.ixigua.com/7172134169580372513?utm_source=xiguastudioB駅:https://www.bilibili.com/video/BV1BY411d7c6/知っている:https://www.zhihu.com/zvideo/1581722694294487040

この記事のコードは参照のみで,実際の使用は自分で調整したり拡張したりできます.


関連性

もっと

wbe3-小さなフライパン模擬ディスク環境操作をどのように実行するか? 信号の精度をテストします.

グオワ取引視察のアラームメッセージには,最後の注文のメッセージが含まれますか? このロボットは,前回の注文が利益だったり損だったりする状態になるまで, 注文を実行しません. ありがとうございました.

13811047519/upload/asset/2a5a9fa2b97561c42c027.jpg どういう意味ですか? どうしたら解決できるのでしょうか?

素晴らしい状況このシグナルで取引をするのに6つの7つのアカウントを追加しました. しかし,一時的にかなり大きいです. 取引所のアカウントのシグナルが完了するまで,次の取引口座のシグナルが実行されます. 連続実行です. 取引のシグナルを同時に実行する方法がありますか?

wbe3-小さなフライパン受け取るシグナルのポリシーでは,プリント収益がないように見えるし,公開も生成されないように見えるので,関連するアカウント情報表のテンプレートを追加して,ポリシー表示を表示してください.

小さな夢公開方針の概要で,ページが自動的に追加されます.

wbe3-小さなフライパンテストは完了しました. しかし,取引後には,戦略評価の概要はありません.

小さな夢OKXインターフェースは,OKXの模擬ディスクテスト環境に切り替えることができる.

グオワありがとうございました. 2つの質問があります. 1つ目は,fmzが自分でpineスクリプトを書けるという点に少し困惑しています.なぜこの記事では,FmzにTradingViewでアラームを送って処理し,取引するのか? 2、私は今,それ自体で良い戦略を見つけました. しかし,ソースコードは使用権がありません. 私は上の方法で間違いを回避したい,私は推送メッセージに追加した,しかしこの推送は,注文時に価格のように見える. 後ろのfmzでは,この価格によって,利益または損失を判断するには,私は少し不明です.

小さな夢メッセージを送信する際にをプッシュして,FMZ上の戦略が情報を処理し,現在の価格対比に基づいて注文するか否かを決定することが実現されるべきです.

小さな夢テストは正常ですか? 私はテストは正常です.

素晴らしい状況ありがとう,ボス

小さな夢FMZは新しい並行機能を追加し,並行に変更できるはずですが,戦略コードは大きく変更される可能性があります.最近,時間があれば並行例をアップグレードします.