[TOC] ¿Qué quieres decir?
Los traders que usan TradingView con frecuencia saben que TradingView puede enviar mensajes a otras plataformas. Anteriormente, también se publicó una política de envío de señales de TradingView en la biblioteca, el contenido del mensaje enviado está escrito en la url de la solicitud, algo inflexible.
Puede que algunos de los estudiantes nuevos vean que el título y la descripción de este artículo son un poco extraños, no importa. Primero explicamos el escenario de las necesidades, los principios.
El primer escenario de demanda: En pocas palabras, tenemos muchos indicadores, estrategias, códigos, etc. que podemos elegir en TradingView, que se pueden ejecutar directamente en TradingView, dibujar líneas, calcular, mostrar señales de negociación, etc. Y TradingView tiene datos de precios en tiempo real, una gran cantidad de datos de líneas K para calcular una variedad de indicadores.
2o Principio:
El programa se centra en cuatro temas, que en pocas palabras son:
Número | El sujeto | Descripción |
---|---|---|
1 | TradingView (Vista de operaciones en el gráfico) | El script PINE se ejecuta en TradingView para enviar señales y acceder a la API de extensión de FMZ |
2 | Plataforma FMZ (en la imagen, la plataforma FMZ en la página web) | Administrar el disco, puede enviar instrucciones de interacción en la página del disco, también puede enviar instrucciones de interacción a los administradores de la plataforma FMZ mediante una interfaz API extendida |
3 | Programas de disco real en el software del administrador (en la imagen, el robot de estrategia de FMZ) | TradingView, el programa en el que se ejecuta la estrategia de ejecución de señales |
4 | El intercambio (exchange en el gráfico) | Intercambio configurado en vivo, el programa de intercambio en vivo del administrador envía directamente la solicitud al intercambio de la orden |
Así que si quieres jugar, tienes que hacer estas preparaciones: 1, Un script que se ejecuta en TradingView y que es responsable de enviar las solicitudes de señal a la interfaz API de extensión de FMZ, requiere que la cuenta de TradingView sea al menos un miembro PRO. 2, Para implementar un programa de administrador en FMZ, se requiere que sea el que pueda acceder a la interfaz de la bolsa (por ejemplo, servidores en Singapur, Japón, Hong Kong, etc.). 3. Configurar en FMZ la API KEY del exchange para realizar el pedido cuando se envíe la señal de TradingView. 4. Necesitas tener una "Estrategia de ejecución de señales TradingView", que es lo que este artículo trata.
En la versión anterior, la política de ejecución de señales de TradingView no era tan flexible, y los mensajes solo podían escribirse en la url de la solicitud enviada por TradingView.
Entonces, en TradingView se puede configurar como en el gráfico, escribir un mensaje en el cuerpo de la solicitud y enviarlo a la interfaz API de extensión de FMZ. ¿Cómo se llama esta interfaz API de extensión de FMZ?
En FMZ, una serie de interfaces de API de extensión, lo que vamos a usar esCommandRobot
La interfaz, que normalmente se llama así:
https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[186515,"ok12345"]
Este es el URL solicitado.query
En el interioraccess_key
ysecret_key
Es una extensión de la plataforma FMZ.API KEY
Así que aquí la demostración está configurada comoxxx
yyyyy
¿Cómo se creó este KEY?https://www.fmz.com/m/account
En la página web de Facebook de la organización, se puede crear una, guardarlas bien y no filtrarlas.
Volviendo al tema, continúa:CommandRobot
El problema de la interfaz.CommandRobot
Interfaz, en la solicitudmethod
El mensaje de Twitter se ha convertido en el siguiente:CommandRobot
。CommandRobot
La función de esta interfaz es enviar un mensaje interactivo a un disco de un ID a través de la plataforma FMZ, por lo que los parámetros son:args
En este caso, el URL de la solicitud es el ID de la aplicación.186515
El programa de disco real envía mensajesok12345
。
Antes, se solicitaba de esta manera a la interfaz CommandRobot de la API de extensión de FMZ, y el mensaje solo se podía escribir como en el ejemplo anterior.ok12345
Si el mensaje está en el cuerpo solicitado, se necesita otra forma:
https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[130350,+""]
Esta solicitud puede ser enviada a través de la plataforma FMZ como un mensaje interactivo al ID para el contenido del cuerpo de la solicitud.130350
Si el mensaje en TradingView está configurado para:{"close": {{close}}, "name": "aaa"}
Entonces, el ID es130350
En el caso de los dispositivos móviles, el disco físico recibirá instrucciones de interacción:{"close": 39773.75, "name": "aaa"}
Para que la política de ejecución de señales de TradingView pueda entender correctamente la instrucción enviada por TradingView al recibir una instrucción de interacción, debe acordarse el formato del mensaje con antelación:
{
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", // 交易量
}
La política está diseñada para ser una arquitectura multi-intercambio, por lo que se pueden configurar varios objetos de intercambio en esta política, es decir, se pueden controlar operaciones de intercambio de varias cuentas diferentes. Sólo con Exchange que especifica el intercambio para operar en la estructura de señales, la configuración 1 es que esta señal opera la cuenta de intercambio correspondiente al primer objeto de intercambio que se agrega.
Ahora podemos diseñar el código de la estrategia, el código completo de la estrategia:
//信号结构
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)
}
}
}
Parámetros estratégicos y interacción:
La política completa de ejecución de señales de TradingView se encuentra en:https://www.fmz.com/strategy/392048
Para configurar el objeto de la bolsa antes de ejecutar la política, en los parámetros de la política, configure "AccessKey de la plataforma FMZ" y "SecretKey de la plataforma FMZ", los dos parámetros, no configure mal.
Imprimirá: la dirección de WebHook que se requiere en TradingView, las instrucciones de acción compatibles, el formato de mensaje; lo importante es la dirección de WebHook:
https://www.fmz.com/api/v1?access_key=22903bab96b26584dc5a22522984df42&secret_key=73f8ba01014023117cbd30cb9d849bfc&method=CommandRobot&args=[505628,+""]
Se puede copiar y pegar directamente la ubicación correspondiente en TradingView.
Si desea simular el envío de señales de TradingView, puede hacer clic en el botón TestSignal en la interacción de la política:
La política envía una solicitud (como una solicitud de señal de envío de TradingView) a sí misma, llama a la interfaz API de extensión de FMZ y envía un mensaje a la política:
{"Flag":"45M103Buy","Exchange":1,"Currency":"BTC_USDT","ContractType":"swap","Price":"16000","Action":"buy","Amount":"1"}
La política actual recibe otro mensaje de interacción y ejecuta:
Y luego pedimos una transacción.
Para usar TradingView, se requiere una cuenta de TradingView de nivel Pro. Hay algunos conocimientos previos que deben explicarse de manera simple antes de probar.
Por ejemplo, un sencillo guión de PINE (algo modificado que encontré en 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, El guión PINE puede incluir información cuando el guión emite la instrucción siguiente
Estos son los símbolos que escribo en el cuadro de "mensajes" de una alarma, por ejemplo:{{strategy.order.contracts}}
Si el cliente no está en contacto con el cliente, entonces se envía un mensaje (de acuerdo con la configuración de la alarma, el envío de correo electrónico, la solicitud de url de webhook, el popup, etc.) que incluye el número de pedidos ejecutados.
{{strategy.position_size}}
- Devuelve el valor de la misma palabra clave en Pine, es decir, el tamaño de la posición actual.{{strategy.order.action}}
- Para la orden ejecutada, devuelva la cadena buy button o sell button.{{strategy.order.contracts}}
- Regresar el número de contratos que se han ejecutado.{{strategy.order.price}}
- Volver el precio de ejecución del pedido.{{strategy.order.id}}
- Devuelve el ID de la orden ejecutada ((se utiliza como la primera de las strings de los parámetros en una de las llamadas de la función que genera la orden: estrategy.entry, strategy.exit o strategy.order)).{{strategy.order.comment}}
- Devuelve la nota de la orden ejecutada (string utilizada en el parámetro de comentarios en una de las llamadas de la función que genera la orden:strategy.entry,strategy.exitSi no se especifica una nota, se usará el valor de estrategy.order.id.{{strategy.order.alert_message}}
- Devuelve el valor del parámetro alert_message, que se puede usar en el código Pine de la política cuando se llama una de las funciones que se usan para ordenar:strategy.exitTambién se puede usar el código de instrucción de la página web de la empresa, o el código de instrucción de la página web de la empresa.{{strategy.market_position}}
- Retorno de la estrategia de la posición actual en forma de una cadena: "long", "flat" o "short".{{strategy.market_position_size}}
- Devuelve el tamaño de la posición actual en forma de valor absoluto (es decir, no negativo).{{strategy.prev_market_position}}
- Retorno de la estrategia en forma de una cadena a la posición anterior: "long", "flat" o "short".{{strategy.prev_market_position_size}}
- Devuelve el tamaño de la posición anterior en forma de valor absoluto (es decir, no negativo).
2. Construir mensajes con "Estrategia de ejecución de señales de TradingView"
{
"Flag":"{{strategy.order.id}}",
"Exchange":1,
"Currency":"BTC_USDT",
"ContractType":"swap",
"Price":"-1",
"Action":"{{strategy.order.comment}}",
"Amount":"{{strategy.order.contracts}}"
}
3. Para que TradingView emita una señal cuando se ejecuta este guión PINE, se requiere que se establezca una alarma cuando se cargue este guión en TradingView
Cuando el script PINE en TradingView inicia una acción de negociación, se envía una solicitud de url webhook.
El disco de FMZ ejecutará la señal.
El video de la calabaza:https://www.ixigua.com/7172134169580372513?utm_source=xiguastudioEstación B:https://www.bilibili.com/video/BV1BY411d7c6/¿Qué es lo que está pasando?https://www.zhihu.com/zvideo/1581722694294487040
El código en el artículo es solo para referencia y puede ser modificado o ampliado por el usuario.
el nombre de la empresa:/ cargar / activo / 1979ae34cdbe7673f64b5.jpg
el nombre de la empresa:Monk, esto está funcionando mal.
N95Mungo, ¿cómo se ejecuta la operación del entorno del disco analógico?
el guohwaPor favor, ¿puede el mensaje de alerta de Tradingview contener el mensaje de la última orden? Quiero saber si la última orden fue ganadora o perdedora, y si la última orden fue perdedora, el robot no ejecutará la operación hasta que la última orden obtenida sea ganadora. ¿Pueden hacerlo, por favor?
13811047519/upload/asset/2a5a9fa2b97561c42c027.jpg Por favor, Dios, ¿qué significa este error y cómo eliminarlo?
Lo mejorDream Big, he añadido 6 a 7 cuentas para hacer transacciones con esta señal, pero por el momento es bastante grande, una cuenta de intercambio de señales completadas para la siguiente cuenta de transacción de señales, es una ejecución en serie, ¿hay una manera de que simultáneamente ejecutar señales de transacción?
Los inventores cuantifican - sueños pequeñosSi no lo haces, puedes eliminar el texto chino de los mensajes de estructura interactiva.
Los inventores cuantifican - sueños pequeñosSi no lo haces, entonces no puedes tener más información sobre el mensaje.
N95En la política de recepción de señales, parece que no se imprimen los ingresos, y la publicación parece que no se genera, así que por favor, agregue un modelo de formulario de información de cuenta relacionado.
Los inventores cuantifican - sueños pequeñosLa página se ha añadido automáticamente.
N95Gracias, amigo, ya lo probé, pero no hay una estrategia de puntuación después de la transacción.
Los inventores cuantifican - sueños pequeñosInterfaz OKX, que puede ser cambiado a un entorno de prueba de disco de simulación de OKX, utilizando el intercambio. IO (("simulate", true), que puede ser cambiado a un entorno de disco de simulación.
el guohwaGracias por la respuesta, tengo dos preguntas: 1, lo que no entiendo es que fmz puede escribir el script pine por sí mismo, ¿por qué este artículo también debe enviar alertas a fmz a través de TradingView y luego procesar y luego negociar? 2, ahora he encontrado una buena estrategia en sí misma, pero sin acceso al código fuente, quiero evitar errores con el método que mencioné anteriormente, lo que usted dice en el mensaje de envío añadido, pero este envío parece ser el precio al momento de realizar el pedido, después en el fmz, ¿cómo a través de este precio para juzgar si es una ganancia o un perjuicio, no tengo un poco de entendimiento.
Los inventores cuantifican - sueños pequeñosDebe ser posible que pujas el contenido de {{strategy.order.price}} en el momento de enviar el mensaje, y luego la estrategia en FMZ procesará la información para decidir si pones un pedido o no en función de la comparación de precios actual.
Los inventores cuantifican - sueños pequeños¿Está todo bien ahora?
Lo mejorMuy bien, gracias al jefe.
Los inventores cuantifican - sueños pequeñosFMZ añade nuevas funciones de concurrencia, que deberían ser convertibles a la concurrencia, aunque el código de la estrategia puede cambiar mucho más.