Funciones para la Gestión de fondos en un Expert Advisor
Introducción
El lenguaje MQL5 proporciona una oportunidad para conseguir una amplia cantidad de informaciones acerca de las actuales condiciones del terminal, del programa MQL5, así como el instrumento financiero y la cuenta de trading. Con el objetivo de organizar las funciones de la gestión de fondos, tenemos que estudiar las propiedades de las dos últimas secciones indicadas antes, además de familiarizarnos con las siguientes funciones:
- SymbolInfoInteger()
- SymbolInfoDouble()
- SymbolInfoString()
- AccountInfoInteger()
- AccountInfoDouble()
- AccountInfoString()
Obtener informaciones sobre el saldo de tu cuenta
Las dos primeras características importantes en una cuenta de trading -el saldo y el valor negociable. Para conseguir estos valores, usa la función AccountInfoDouble():
double balance=AccountInfoDouble(ACCOUNT_BALANCE); double equity=AccountInfoDouble(ACCOUNT_EQUITY);
Lo siguiente que nos interesa es el volumen de los fondos del depósito para las posiciones abiertas, y el total de ganancias o perdidas pendientes en la cuenta, para todas las posiciones abiertas.
double margin=AccountInfoDouble(ACCOUNT_MARGIN); double float_profit=AccountInfoDouble(ACCOUNT_PROFIT);
Para poder abrir nuevas posiciones o fortalecer las que ya existen, necesitamos recursos libres, que no participan en el depósito.
double free_margin=AccountInfoDouble(ACCOUNT_FREEMARGIN);
Hay que señalar aquí que los valores anteriores se expresan en términos monetarios.
Los valores monetarios, devueltos por la función AccountInfoDouble(), se expresan en la divisa del depósito. Para averiguar cuál es la divisa del depósito, usa la función AccountInfoString().
string account_currency=AccountInfoString(ACCOUNT_CURRENCY);
El nivel de los fondos propios
La cuenta tiene otra característica importante -el nivel al que se produce el Stop Out (cierre forzado de las posiciones debido a la escasez de los fondos propios necesarios para poder mantener las posiciones abiertas). Para conseguir este valor, usa otra vez la función AccountInfoDouble():
double stopout_level=AccountInfoDouble(ACCOUNT_MARGIN_SO_SO);
La función sólo devuelve el valor en sí, pero no especifica en que unidades está expresado. Hay dos formas de determinar el nivel de Stop Out: en porcentaje y en divisa. Para averiguarlo, usa la función AccountInfoInteger():
//--- Obtener la divisa de la cuenta string account_currency=AccountInfoString(ACCOUNT_CURRENCY); //--- Nivel de Stop Out (cierre forzoso) double stopout_level=AccountInfoDouble(ACCOUNT_MARGIN_SO_SO); //--- Modo de Stop Out ENUM_ACCOUNT_STOPOUT_MODE so_mode=(ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE); if(so_mode==ACCOUNT_STOPOUT_MODE_PERCENT) PrintFormat("El nivel de Stop Out en porcentaje %.2f%%",stopout_level); else PrintFormat("El nivel de Stop Out en divisa %.2f %s",stopout_level,account_currency);
Información adicional sobre la cuenta
A menudo, los cálculos requieren conocer el volumen del apalancamiento proporcionado en la cuenta de trading. Puedes averiguar esta información mediante la función AccountInfoInteger():
int leverage=(int)AccountInfoInteger(ACCOUNT_LEVERAGE);Para evitar la ejecución accidental de un Expert Advisor no regulado con una cuenta real, tienes que saber el tipo de cuenta.
ENUM_ACCOUNT_TRADE_MODE mode=(ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE); switch(mode) { case ACCOUNT_TRADE_MODE_DEMO: Comment("Cuenta Demo"); break; case ACCOUNT_TRADE_MODE_CONTEST: Comment(com,"Cuenta de Competición"); break; case ACCOUNT_TRADE_MODE_REAL: Comment(com,"Cuenta Real"); break; default: Comment(com,"Cuenta de tipo desconocido"); }El trading no es posible en cada cuenta, por ejemplo, en la cuentas para competiciones, no se pueden realizar operaciones de trading antes del comienzo de la competición. Se puede obtener esta información con la función AccountInfoInteger():
bool trade_allowed=(bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED); if(trade_allowed) Print("El trading está permitido"); else Print(com,"El trading no está permitido");
El hecho de que el trading esté permitido en esta cuenta, no significa que el Expert Advisor tiene derecho a hacerlo. Para averiguar si el Expert Advisor tiene permiso para hacer trading, escribe:
if(trade_allowed) { bool trade_expert=(bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT); if(trade_expert) Print("Los Expert Advisors tienen permiso para el trading"); else Print("Los Expert Advisors no tienen permiso para el trading");
Se pueden encontrar estos ejemplos en el Expert Advisor Account_Info.mq5 adjunto. Se pueden utilizar en los programas de MQL5 de cualquier nivel de complejidad.
Información acerca del instrumento
Cada instrumento financiero tiene sus propias descripciones y se coloca en una ruta que lo caracteriza. Si abrimos la ventana de propiedades de EURUSD en el terminal, veremos algo así:
En este caso, la descripción de EURUSD es -"EURUSD, EURO vs US Dollar". Se obtiene esta información mediante la función SymbolInfoString():
string symbol=SymbolInfoString(_Symbol,SYMBOL_DESCRIPTION); Print("Símbolo: "+symbol); string symbol_path=SymbolInfoString(_Symbol,SYMBOL_PATH); Print("Ruta: "+symbol_path);
Para averiguar el volumen de un contrato estándar, usa SymbolInfoDouble():
double lot_size=SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE); Print("Contrato estándar: "+DoubleToString(lot_size,2));
Es una característica de los instrumentos del mercado de divisas (FOREX) para vender una divisa mientras se compra otra. Se indica el contrato en la divisa, y esta última es necesaria para llevar a cabo la compra. Se trata de la divisa de referencia, y se puede obtener mediante la función SymbolInfoString():
string base_currency=SymbolInfoString(_Symbol,SYMBOL_CURRENCY_BASE); Print("Divisa de referencia: "+base_currency);
Los cambios de precio en el instrumento llevan a un cambio en el precio del activo adquirido, y por lo tanto, a una variación del beneficio para una posición abierta (el beneficio puede ser negativo si la posición está perdiendo). Por lo tanto, el cambio de precio lleva a cambios en los ingresos, expresados en una divisa concreta. A esta divisa se le llama la divisa cotizada. Para el par de divisas EURUSD, la divisa de referencia suele ser el Euro, y la divisa cotizada suele ser el dólar estadounidense. Para obtener la divisa cotizada puedes utilizar también la función SymbolInfoString():
string profit_currency=SymbolInfoString(_Symbol,SYMBOL_CURRENCY_PROFIT); Print("Cotizaciones de la divisa: "+profit_currency);
Para abrir una posición en el instrumento, necesitas fondos, que también se expresan en una divisa determinada. Esta divisa se llama la divisa del depósito o de margen. Para los instrumentos del mercado FOREX la divisa de referencia y de depósito suele ser la misma. Para obtener el valor de la divisa de depósito, puedes utilizar la función SymbolInfoString():
string margin_currency=SymbolInfoString(_Symbol,SYMBOL_CURRENCY_MARGIN); Print("Depósito de la divisa: "+margin_currency);
Todas las funciones descritas están en el código del Expert Advisor Symbol_Info.mq5. En la siguiente figura se describe la salida de información del símbolo EURUSD, mediante la función Comment().
El cálculo del volumen del depósito
La información más buscada por los traders en relación a los instrumentos financieros, es la cantidad necesaria de fondos para poder abrir una posición en ellos. Sin saber cuánto dinero hace falta para comprar o vender un determinado número de lotes, no podemos implementar un sistema Expert Advisor para la gestión de fondos. Además, se complica el control del saldo de la cuenta.
Si tienes dificultades en entender lo que viene a continuación, te recomiendo leer el artículo ABC del trading en el mercado de divisas. Las explicaciones allí descritas son también válidas para este artículo.
Necesitamos calcular el tamaño del margen de la divisa del depósito, es decir, volver a calcular el depósito desde la divisa hipotecaria hasta la divisa del depósito, dividiendo el valor obtenido por el valor del apalancamiento de la cuenta en cuestión. Para hacerlo escribimos la función GetMarginForOpening()://+---------------------------------------------------------------------+ //| Devolver la cantidad necesaria de valores para abrir una posición | //+---------------------------------------------------------------------+ double GetMarginForOpening(double lot,string symbol,ENUM_POSITION_TYPE direction) { double answer=0; //--- ... //--- Devolver el resultado - cantidad de valores en la divisa de la cuenta, necesaria para la posición abierta en un determinado volumen return(answer); }
¿dónde?:
- lot -el volumen de la posición abierta;
- symbol -el nombre del instrumento financiero;
- La dirección de la posición prevista.
- divisa del depósito
- divisa hipotecaria
- cotizaciones de divisas (pueden hacer falta para los Pares de cruces de divisas)
- el volumen del contrato
Escribe lo siguiente en el lenguaje MQL5:
//--- Obtener el volumen del contrato double lot_size=SymbolInfoDouble(symbol,SYMBOL_TRADE_CONTRACT_SIZE); //--- Obtener la divisa del contrato string account_currency=AccountInfoString(ACCOUNT_CURRENCY); //--- Divisa del depósito string margin_currency=SymbolInfoString(_Symbol,SYMBOL_CURRENCY_MARGIN); //--- Divisa de ganancia string profit_currency=SymbolInfoString(_Symbol,SYMBOL_CURRENCY_PROFIT); //--- Cálculo de divisa string calc_currency=""; //--- Cotización inversa - true, Cotización directa - false bool mode;
La variable mode afecta a la manera de calcular el volumen del contrato en la divisa del depósito. Teniendo en cuenta los ejemplos, asumimos que en todos los siguientes casos la divisa del depósito es el dólar estadounidense.
Los pares de divisas se suelen dividir en tres categorías:
- Pares de divisas principales -el tipo de cambio del dólar estadounidense a una determinada divisa. Ejemplos: USDCHF, USDCAD, USDJPY, USDSEK;
- Pares de divisas inversas - el tipo de cambio de una divisa particular al dolar estadounidense. Ejemplos: EURUSD, GBPUSD, AUDUSD, NZDUSD;
- Pares de cruces de divisas - un par de divisa en el cual no hay dólar estadounidense. Ejemplos: AUDCAD, EURJPY, EURCAD.
1. EURUSD - el par de divisas inversas.
Llamaremos pares de divisas inversas a aquellos pares con la misma divisa cotizada y divisa de cuenta. En nuestros ejemplos, la divisa de la cuenta es el dólar estadounidense, por lo que nuestra clasificación de los pares de divisas va a coincidir con la clasificación generalmente aceptada. Pero si tu cuenta de trading utiliza una divisa distinta (que no sea USD), no coincidirá. En este caso, ten en cuenta la divisa de la cuenta, para poder entender todas las eventuales explicaciones.
El volumen del contrato para EURUSD - 100 000 euros. Necesitamos expresar los 100 000 euros en la divisa del depósito -dólares estadounidenses. Para hacerlo, necesitas conocer el tipo de cambio, en función del cual se puede contar el euro en dólares. Introducimos el concepto de la divisa del cálculo, eso es, la divisa necesaria para convertir la divisa hipotecaria a una divisa de depósito.
//--- Divisa para el cálculo string calc_currency="";
Afortunadamente, el par de divisas EURUSD muestra el tipo de cambio del euro frente al dólar, y por lo tanto, en este caso el símbolo EURUSD, para el cual es necesario calcular el volumen hipotecario, es precisamente el tipo de cambio:
//--- Si la divisa de beneficio y de cuenta es la misma if(profit_currency==account_currency) { calc_currency=symbol; mode=true; }
Le hemos asignado el valor true a mode, lo que significa que para transferir euros a dólares (se convierte la divisa hipotecaria en divisa de depósito), multiplicaremos el tipo de cambio actual de EURUSD por el volumen del contrato. Si mode = false, dividimos el volumen del contrato por el tipo de cambio de la divisa del cálculo. Para obtener los precios actuales en el instrumento, usa la función SymbolInfoTick().
//--- Conocemos la divisa del cálculo, vamos a obtener sus últimos precios MqlTick tick; SymbolInfoTick(calc_currency,tick);
Esta función coloca el precio y tiempo actuales de la última actualización de precios en la variable del tipo MqlTick -esta estructura se ha diseñado especialmente para este propósito.
Por lo tanto, es suficiente para obtener el último precio de este símbolo, lo multiplicas por el volumen del contrato y luego por el número de lotes. Pero, teniendo en cuenta que el instrumento tiene un precio de compra y un precio de venta, ¿que precio escogemos para el cálculo? lógicamente: si estamos comprando, el precio para los cálculos es igual al precio de Compra (Ask price), y si estamos vendiendo, será el precio de venta (Bid price).
//--- Ahora tenemos todo para el cálculo double calc_price; //--- Cálculo para Compra if(direction==POSITION_TYPE_BUY) { //--- Cotización inversa if(mode) { //--- Cálculo mediante precio de Compra para cotización inversa calc_price=tick.ask; answer=lot*lot_size*calc_price; } } //--- Cálculo para Venta if(direction==POSITION_TYPE_SELL) { //--- Cotización inversa if(mode) { //--- Cálculo mediante precio de Venta para cotización inversa calc_price=tick.bid; answer=lot*lot_size*calc_price; } }
Por lo tanto, en nuestro ejemplo, la divisa de depósito para el símbolo EURUSD es Euro, el volumen del contrato es 100 000 y el último precio de Compra = 1,2500. La divisa de la cuenta -dólar estadounidense, y la divisa del cálculo es el mismo par de divisa EURUSD. Multiplica 100 000 por 1,2500 y obtienes 125 000 dólares estadounidenses -esto es exactamente a cuanto está un contrato estándar para la compra de 1 lote EURUSD, si el precio de Compra = 1,2500.
Podemos concluir que si la divisa de cotización es igual a la divisa de la cuenta, para obtener el valor de un lote de la divisa de cuenta, multiplicamos simplemente el volumen del contrato por el precio apropiado, Compra o Venta, en función de la dirección prevista de la posición.
margin=lots*lot_size*rate/leverage;
2. USDCHF - el par de divisas principal
La divisa hipotecaria y la divisa de cuenta para el par USDCHF -el dólar estadounidense. Llamaremos a los pares de divisas donde la divisa hipotecaria es la misma que la divisa de la cuenta, como pares de divisas principales. Volumen del contrato - 100 000 Este es el caso más sencillo, simplemente devuelve el producto.
//--- si el símbolo de la divisa de referencia y la divisa de depósito son iguales if(margin_currency==account_currency) { calc_currency=symbol; //--- simplemente devuelve el valor del contrato, multiplicado por el número de lotes return(lot*lot_size); }
Si la divisa del depósito y la divisa de la cuenta coinciden, entonces el valor del depósito en la divisa de la cuenta es igual al producto del contrato estándar por el número de lotes (contratos) dividido por el volumen de apalancamiento.
margin=lots*lot_size/leverage;
3. CADCHF - el par de cruces de divisas
Se toma el par de divisas CADCHF como ejemplo, y se puede aplicar a cualquier otro par en el que coinciden la divisa del depósito y la divisa cotizado con la divisa de la cuenta. Estos pares de divisas se llaman cruces, ya que para calcular su diferencial y beneficio, necesitamos conocer el tipo de cambio de algún otro par de divisas, que hay que cruzar con una de las divisas.
Los pares de cruces de divisas suelen ser los pares en los que la cotización no utiliza el dólar estadounidense. Pero llamaremos a todos los pares que no incluyen la divisa de la cuenta en sus cotizaciones, pares de cruces de divisas. Por lo tanto, si la divisa de la cuenta es el Euro, entonces el par GBPUSD sería un par de cruces de divisas, ya que la divisa del depósito es la libra esterlina y la divisa cotizada es el dólar estadounidense. En este caso, para el cálculo del diferencial, expresaremos la libra esterlina (GBP) en euro (EUR).
Pero continuamos considerando el ejemplo donde el símbolo es el par de divisas CADCHF. La divisa del depósito es el dólar canadiense (CAD) y no coincide con el dólar estadounidense (USD). La divisa cotizada es franco suizo (CHF) y no coincide con el dólar estadounidense (USD).
Sólo podemos decir que el depósito para la apertura de una posición en 1 lote es igual a 100 000 dólares canadienses. Nuestra tarea es volver a calcular el depósito en la divisa de la cuenta en dólares estadounidenses. Para ello, necesitamos averiguar el par de divisas, el tipo de cambio que contiene el dólar estadounidense y la divisa del depósito - CAD. En total hay dos opciones posibles:
- CADUSD
- USDCAD
Tenemos los datos de salida de CADCHF:
margin_currency=CAD (dólar canadiense) profit_currency=CHF (franco suizo)
No sabemos de antemano cuales son los pares de divisas existentes en el terminal, y desde el punto de vista de MQL5, ninguna opción es mejor que la otra. Por lo tanto, escribimos la función GetSymbolByCurrencies(), que para el conjunto de divisas dado, nos dará la primera coincidencia de pares de divisas para los cálculos.
//+------------------------------------------------------------------+ //| Devuelve el símbolo divisa del depósito y la divisa de ganancia | //+------------------------------------------------------------------+ string GetSymbolByCurrencies(string margin_currency,string profit_currency) { //--- Procesar en bucle todos los símbolos que se muestran en la ventana de Observación del Mercado for(int s=0;s<SymbolsTotal(true);s++) { //--- Obtener el nombre del símbolo por número en la ventana de Observación del Mercado string symbolname=SymbolName(s,true); //--- Obtener divisa del depósito string m_cur=SymbolInfoString(symbolname,SYMBOL_CURRENCY_MARGIN); //--- Obtener divisa de beneficio (beneficio sobre el cambio de precio) string p_cur=SymbolInfoString(symbolname,SYMBOL_CURRENCY_PROFIT); //--- si el símbolo coincide con ambas divisas, devolver el nombre del símbolo if(m_cur==margin_currency && p_cur==profit_currency) return(symbolname); } return(NULL); }
Como se puede observar en el código, empezamos enumerando los símbolos presentes en la ventana "Observación del Mercado" (la función SymbolsTotal() con el parámetro "true" nos dará esta cantidad). Para obtener el nombre de cada símbolo mediante el número de la lista de "Observación del Mercado", usamos la función SymbolName() con el parámetro true. Si asignamos el valor "false" al parámetro, lo que haremos sería enumerar todos los símbolos presentes en el servidor de trading, y esto suele ser mucho más de lo que está seleccionado en el terminal.
A continuación, utilizamos el nombre del símbolo para obtener la divisa del depósito y de cotización, y las comparamos con aquellas que ha recibido la función GetSymbolByCurrencies(). En caso de éxito, devolvemos el nombre del símbolo, y la tarea de la función se ha llevado a cabo con éxito y antes de lo previsto. Si el bucle llega a su fin, y alcanzamos la última línea de la función, entonces no ocurre nada y el símbolo no ha sido encontrado, -devuelve NULL.
Ahora que hemos obtenido la divisa del cálculo para el par de cruces de divisas mediante la función GetSymbolByCurrencies(), haremos dos intentos: en el primer intento buscaremos el símbolo, la divisa del depósito que es margin_currency (divisa del depósito CADCHF - CAD), y la divisa cotizada que es la divisa de la cuenta (USD). En otras palabras, estamos buscando algo parecido al par CADUSD.
//--- Si aún no se ha terminado el cálculo de la divisa //--- entonces tenemos un cruce de divisas if(calc_currency="") { calc_currency=GetSymbolByCurrencies(margin_currency,account_currency); mode=true; //--- si el valor obtenido es igual a NULL, este símbolo no se encuentra if(calc_currency==NULL) { //--- Vamos a intentar hacerlo al revés calc_currency=GetSymbolByCurrencies(account_currency,margin_currency); mode=false; } }
Si fallan los intentos, intenta encontrar otra opción: busca un símbolo que tiene account_currency (USD) por divisa de depósito, y margin_currency (divisa del depósito para CADCHF - CAD) por divisa cotizada. Estamos buscando algo parecido a USDCAD.
Ahora que hemos encontrado el par de divisas para los cálculos, puede ser una de las dos opciones -principal o inversa. La variable mode toma el valor "true" para el par de divisas inversas. Si tenemos un par de divisas principal, entonces el valor seria igual a "false". En el caso del valor "true", lo multiplicamos por el tipo de cambio del par de divisas, y en el caso del "false" - lo dividimos por el valor del depósito de un contrato estándar en la divisa de la cuenta.
Aquí está el cálculo definitivo del volumen del depósito en la divisa de la cuenta para la divisa de cálculo encontrada. Es válido para las dos opciones -los pares de divisas principales e inversas.
//--- Conocemos la divisa del cálculo, vamos a obtener sus últimos precios MqlTick tick; SymbolInfoTick(calc_currency,tick); //--- Ahora lo tenemos todo para el cálculo double calc_price; //--- Cálculo para Compra if(direction==POSITION_TYPE_BUY) { //--- Cotización inversa if(mode) { //--- Cálculo mediante el precio de Compra para la cotización inversa calc_price=tick.ask; answer=lot*lot_size*calc_price; } //--- Cotización directa else { //--- Cálculo mediante el precio de Venta para la cotización inversa calc_price=tick.bid; answer=lot*lot_size/calc_price; } } //--- Cálculo para Venta if(direction==POSITION_TYPE_SELL) { //--- Cotización inversa if(mode) { //--- Cálculo mediante el precio de Venta para la cotización inversa calc_price=tick.bid; answer=lot*lot_size*calc_price; } //--- Direct quote else { //--- Cálculo mediante el precio de Compra para la cotización inversa calc_price=tick.ask; answer=lot*lot_size/calc_price; } }
Devuelve el resultado obtenido
//--- Devolver el resultado -cantidad de fondo en la divisa de la cuenta, necesaria para la posición abierta en el volumen indicado return (Answer);
La función GetMarginForOpening() finaliza su trabajo en este punto. Lo último que hay que hacer es dividir el valor obtenido por el volumen del apalancamiento proporcionado - y a continuación obtendremos el valor del diferencial para las posiciones abiertas con la cantidad especificada en la dirección supuesta. Ten en cuenta que para los símbolos, que sean del par inverso o de cruce, el valor del diferencial variará con cada tick.
Está es una parte del código del Expert Advisor SymbolInfo_Advanced.mq5. Se adjunta el código completo como archivo.
//+------------------------------------------------------------------+ //| Función Expert tick | //+------------------------------------------------------------------+ void OnTick() { //--- Variable de cadena para comentario string com="\r\n"; StringAdd(com,Symbol()); StringAdd(com,"\r\n"); //--- Volumen del contrato estándar double lot_size=SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE); //--- Divisa del depósito string margin_currency=SymbolInfoString(_Symbol,SYMBOL_CURRENCY_MARGIN); StringAdd(com,StringFormat("Contrato estándar: %.2f %s",lot_size,margin_currency)); StringAdd(com,"\r\n"); //--- Apalancamiento int leverage=(int)AccountInfoInteger(ACCOUNT_LEVERAGE); StringAdd(com,StringFormat("Apalancamiento: 1/%d",leverage)); StringAdd(com,"\r\n"); //--- Cálculo del valor del contrato en la divisa de la cuenta StringAdd(com,"El depósito para la apertura de posiciones en 1 lote "); //--- Cálculo del diferencial mediante el apalancamiento double margin=GetMarginForOpening(1,Symbol(),POSITION_TYPE_BUY)/leverage; StringAdd(com,DoubleToString(margin,2)); StringAdd(com," "+AccountInfoString(ACCOUNT_CURRENCY)); Comment(com); }
Y tenemos el resultado de la operación en el gráfico.
Conclusión
Los ejemplos proporcionados demuestran lo sencillo y fácil que es obtener informaciones sobre los datos más relevantes de la cuenta de trading y sobre las propiedades de los instrumentos financieros.
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/113
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso