avatar of 发明者量化-小小梦 发明者量化-小小梦
Seguir Mensajes Privados
4
Seguir
1271
Seguidores

Otra solución de estrategia de ejecución de señales de TradingView

Creado el: 2022-11-30 10:52:07, Actualizado el: 2025-05-16 16:18:13
comments   17
hits   4333

[TOC]

Otra solución de estrategia de ejecución de señales de TradingView

Otra solución de estrategia de ejecución de señales de TradingView

Los traders que utilizan frecuentemente TradingView saben que TradingView puede enviar mensajes a otras plataformas. Anteriormente, se publicaba una estrategia de envío de señales de TradingView en la biblioteca de documentos. El contenido del mensaje enviado estaba codificado en la URL de la solicitud, lo que era un tanto inflexible. En este artículo, rediseñaremos una estrategia de ejecución de señales de TradingView de una manera diferente.

Escenarios y principios

Algunos estudiantes novatos pueden confundirse al ver el título de este artículo y la descripción anterior, ¡no importa! Aclararemos primero los escenarios y principios de la demanda. Déjame saber de qué estoy hablando. Bueno, vayamos al grano.

  1. Escenario de demanda: Después de toda esta charla, ¿qué se supone que hace esta cosa? En pocas palabras, tenemos muchos indicadores, estrategias, códigos, etc. que podemos elegir para usar en TradingView. Estos se pueden ejecutar directamente en TradingView y pueden dibujar líneas, calcular, mostrar señales comerciales, etc. Además, TradingView tiene datos de precios en tiempo real y suficientes datos de línea K para facilitar el cálculo de varios indicadores. Estos códigos de script en TradingView se denominan lenguaje PINE. El único inconveniente es el trading real en TradingView. Aunque el lenguaje PINE ya es compatible con FMZ, también se puede ejecutar en tiempo real. Sin embargo, también hay fanáticos incondicionales de TradingView que aún esperan poder realizar pedidos en función de las señales enviadas por los gráficos de TradingView. Esta demanda también puede ser resuelta por FMZ. En este artículo explicamos los detalles específicos de esta solución.

  2. Principio:

Otra solución de estrategia de ejecución de señales de TradingView

El plan completo consta de cuatro cuerpos principales, que son brevemente:

Número de serie cuerpo principal describir
1 TradingView (Vista de trading en la imagen) TradingView ejecuta el script PINE, que puede enviar señales y acceder a la interfaz API extendida de FMZ.
2 Plataforma FMZ (Plataforma FMZ (sitio web) en la imagen) Administre el mercado real, envíe instrucciones interactivas en la página del mercado real y también use la interfaz API extendida para permitir que la plataforma FMZ envíe instrucciones interactivas al programa de estrategia del mercado real en el custodio.
3 El programa real en el software de alojamiento (robot de estrategia FMZ en la imagen) El programa real que ejecuta la estrategia de ejecución de señales de TradingView
4 Intercambio (intercambio en la imagen) El intercambio configurado en el mercado real, el intercambio al que el programa del mercado real en el custodio envía directamente la solicitud para colocar una orden

Entonces, si quieres jugar así, necesitas los siguientes preparativos: 1. El script que se ejecuta en TradingView es responsable de enviar solicitudes de señales a la interfaz API extendida de FMZ. La cuenta de TradingView debe ser al menos miembro PRO. 2. Implementar un programa de custodia en FMZ, que debe poder acceder a la interfaz de intercambio (como servidores en Singapur, Japón, Hong Kong, etc.). 3. Configure la API KEY del exchange en FMZ para operar (colocar una orden) cuando se envíe la señal de TradingView. 4. Es necesario contar con una “estrategia de ejecución de señales de TradingView”, que es de lo que trata principalmente este artículo.

Estrategia de ejecución de señales de TradingView

La versión anterior de “Estrategia de ejecución de señales de TradingView” no estaba diseñada para ser flexible y el mensaje solo podía codificarse en la URL de la solicitud enviada por TradingView. Si queremos que TradingView escriba alguna información variable en el Cuerpo al enviar un mensaje, no hay nada que podamos hacer en este momento. Por ejemplo, el contenido del mensaje en TradingView se ve así:

Otra solución de estrategia de ejecución de señales de TradingView

Luego, TradingView se puede configurar como se muestra en la figura, escribiendo el mensaje en el cuerpo de la solicitud y enviándolo a la interfaz API extendida de FMZ. Entonces, ¿cómo se llama a esta interfaz API extendida de FMZ?

Entre la serie de interfaces API extendidas de FMZ, vamos a utilizarCommandRobotEsta interfaz normalmente se llama así:

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

Esta URL de solicitudqueryEnaccess_keyysecret_keyEs una extensión de la plataforma FMZAPI KEY, aquí demostramos cómo configurarloxxxyyyyy. ¿Cómo crear esta CLAVE? En esta página:https://www.fmz.com/m/account, simplemente crea uno, guárdalo adecuadamente y nunca lo divulgues.

Otra solución de estrategia de ejecución de señales de TradingView

Volviendo al tema, continuemosCommandRobotProblema de interfaz. Si necesitas accederCommandRobotInterfaz, en la solicitudmethodSimplemente configúrelo en:CommandRobotCommandRobotLa función de esta interfaz es enviar un mensaje interactivo a un disco real de un ID determinado a través de la plataforma FMZ, por lo que los parámetrosargsEl contenido de la solicitud es el ID real y el mensaje. El ejemplo de URL de solicitud anterior es para enviar una solicitud al ID186515Programa real, enviar mensajeok12345

Anteriormente, este método se utilizaba para solicitar la interfaz CommandRobot de la API de extensión FMZ. El mensaje solo podía codificarse de forma rígida, como en el ejemplo anterior.ok12345. Si el mensaje está en el cuerpo de la solicitud, se necesita otro método:

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

De esta manera, la solicitud puede ser enviada a través de la plataforma FMZ, y el contenido del cuerpo de la solicitud se envía como un mensaje interactivo al usuario con ID.130350El verdadero negocio. Si el mensaje en TradingView está configurado como:{"close": {{close}}, "name": "aaa"}, entonces el ID es130350El disco real recibirá instrucciones interactivas:{"close": 39773.75, "name": "aaa"}

Para que la “Estrategia de ejecución de señales de TradingView” comprenda correctamente la instrucción enviada por TradingView cuando recibe la instrucción interactiva, el formato del mensaje debe acordarse de antemano:

{
    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 estrategia está diseñada como una arquitectura multi-intercambio, por lo que se pueden configurar múltiples objetos de intercambio en esta estrategia, lo que significa que se pueden controlar las operaciones de pedidos de múltiples cuentas diferentes. Simplemente use Exchange en la estructura de la señal para especificar el intercambio que se va a operar. Si se establece en 1, significa que esta señal operará la cuenta de intercambio correspondiente al primer objeto de intercambio agregado. Si se va a operar el contrato al contado, establezca ContractType en spot; para futuros, escriba el contrato específico, por ejemplo, escriba swap para contratos perpetuos. Para el precio de orden de mercado, simplemente pase -1. Las configuraciones de acción son diferentes para futuros, spot, posiciones de apertura y cierre, y no se pueden configurar incorrectamente.

A continuación, puedes diseñar el código de estrategia. El código de estrategia completo es:

//信号结构
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 de la estrategia e interacciones:

Otra solución de estrategia de ejecución de señales de TradingView

「Estrategia de ejecución de señales de TradingView」Dirección completa de la estrategia: https://www.fmz.com/strategy/392048

Prueba sencilla

Antes de ejecutar la estrategia, debe configurar el objeto de intercambio y establecer los dos parámetros “Clave de acceso de la plataforma FMZ” y “Clave secreta de la plataforma FMZ” en los parámetros de la estrategia. Asegúrese de no configurarlos incorrectamente. Al ejecutarlo se muestra:

Otra solución de estrategia de ejecución de señales de TradingView

Se imprimirá en secuencia lo siguiente: la dirección de WebHook que debe completarse en TradingView, las instrucciones de acción compatibles y el formato del mensaje. Lo importante es la dirección del WebHook:

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

Simplemente cópielo, péguelo y escríbalo en la posición correspondiente en TradingView.

Si desea simular que TradingView envía una señal, puede hacer clic en el botón TestSignal en la interacción de la estrategia:

Otra solución de estrategia de ejecución de señales de TradingView

Esta estrategia enviará una solicitud por sí misma (simulando que TradingView envía una solicitud de señal), llamará a la interfaz API extendida FMZ y enviará un mensaje a la estrategia misma:

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

La estrategia actual recibirá otro mensaje interactivo y se ejecutará:

Otra solución de estrategia de ejecución de señales de TradingView

Y haz un pedido.

Pruebas con TradingView en escenarios del mundo real

Para utilizar la prueba de TradingView, necesita una cuenta de TradingView de nivel Pro. Antes de realizar la prueba, hay algunos conocimientos previos que deben explicarse brevemente.

Tome un script PINE simple (lo encontré en TradingView y lo modifiqué un poco) como ejemplo

//@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 script PINE puede adjuntar cierta información cuando el script emite una instrucción de orden

Los siguientes son marcadores de posición. Por ejemplo, escribí en el cuadro “Mensaje” de la alarma:{{strategy.order.contracts}}, luego, cuando se activa una orden, se enviará un mensaje (según la configuración de la alarma, el envío de correo electrónico, la solicitud de URL del webhook, la ventana emergente, etc.) y el mensaje incluirá la cantidad de la orden ejecutada. tiempo.

{{strategy.position_size}} - Devuelve el valor de la misma palabra clave en Pine, que es el tamaño de la posición actual. {{strategy.order.action}} - Devuelve la cadena “comprar” o “vender” para una orden ejecutada. {{strategy.order.contracts}} - Devuelve el número de contratos para la orden ejecutada. {{strategy.order.price}} - Devuelve el precio al que se ejecutó la orden. {{strategy.order.id}} - Devuelve el ID de la orden ejecutada (una cadena utilizada como primer argumento en una de las llamadas de función que generaron una orden: strategy.entry, strategy.exit o strategy.order). {{strategy.order.comment}} - Devuelve el comentario de la orden ejecutada (la cadena utilizada en el parámetro comment en una de las llamadas de función que generaron la orden: strategy.entry, strategy.exit o strategy.order). Si no se especifica ninguna anotación, se utilizará el valor de strategy.order.id. {{strategy.order.alert_message}} - Devuelve el valor del parámetro alert_message, que se puede utilizar en el código Pine de la estrategia al llamar a una de las funciones para realizar órdenes: strategy.entry, strategy.exit o strategy.order. Esta función solo es compatible con Pine v4. {{strategy.market_position}} - Devuelve la posición actual de la estrategia como una cadena: “larga”, “plana” o “corta”. {{strategy.market_position_size}} - Devuelve el tamaño de la posición actual como un valor absoluto (es decir, un número no negativo). {{strategy.prev_market_position}} - Devuelve la última posición de la estrategia como una cadena: “larga”, “plana” o “corta”. {{strategy.prev_market_position_size}} - Devuelve el tamaño de la posición anterior como un valor absoluto (es decir, un número no negativo).

  1. Combine la “Estrategia de ejecución de señales de TradingView” para construir mensajes
{
    "Flag":"{{strategy.order.id}}",
    "Exchange":1,
    "Currency":"BTC_USDT",
    "ContractType":"swap",
    "Price":"-1",
    "Action":"{{strategy.order.comment}}",
    "Amount":"{{strategy.order.contracts}}"
}
  1. Deje que TradingView emita una señal cuando se esté ejecutando este script PINE. Debe configurar una alarma cuando se cargue este script en TradingView

Otra solución de estrategia de ejecución de señales de TradingView

Cuando el script PINE en TradingView activa una acción comercial, se envía una solicitud de URL de webhook.

Otra solución de estrategia de ejecución de señales de TradingView

Otra solución de estrategia de ejecución de señales de TradingView

El comercio real de FMZ ejecutará esta señal.

Otra solución de estrategia de ejecución de señales de TradingView

Otra solución de estrategia de ejecución de señales de TradingView

URL del vídeo

Vídeo de Xigua: https://www.ixigua.com/7172134169580372513?utm_source=xiguastudio Estación B: https://www.bilibili.com/video/BV1BY411d7c6/ Zhihu: https://www.zhihu.com/zvideo/1581722694294487040

Los códigos del artículo son solo de referencia. Puedes modificarlos y ampliarlos para su uso real.