Calculadora de señales

Vladimir Karputov | 29 abril, 2016


Índice


Introducción

La pregunta más frecuente que surge a los suscriptores suele ser: "¿Puedo suscribirme a una señal NNN, y qué volumen de posición se copiará en mi cuenta comercial?". Este artículo ayudará a crear una calculadora de señales: un ayudante estupendo para aquellos que deseen suscribirse a una señal. Asimismo, en este artículo se muestra una breve guía para el uso de las señales de la calculadora.

La propia calculadora es un panel basado en la clase CDialog. En este panel se usan los elementos siguientes:

La calculadora de señales funciona con la base de señales disponibles en el terminal. Esto asegura la máxima compatibilidad entre la señal y su cuenta comercial, ya que en el terminal se lleva a cabo un filtrado adicional de señales según varios índices. La tarea principal del filtrado es eliminar del campo visual del usuario las señales con mal rendimiento en el copiado o eliminar las señales que no se pueden copiar.

La calculadora presentada en este artículo se puede descargar de forma gratuita del Mercado tanto para MetaTrader 5, como para MetaTrader 4:


1. Limitaciones de uso

Debe entenderse claramente que en el terminal, en la pestaña "Señales" sólo se muestran las señales que sean compatibles al máximo con la cuenta comercial del suscriptor. En otras palabras, en el terminal, usted no verá todas las señales disponibles en el escaparate de señales en la página web. Además, al cambiar en el terminal de un servidor comercial (cuenta comercial) a otro, usted podrá ver que la lista de señales en el terminal cambia.


2. Instrucciones de funcionamiento de la calculadora de señales

2.1. Inicio de trabajo

Para que la calculadora funcione, necesita una base acutalizada de señales comerciales en el terminal. Para ello, es necesario activar la pestaña "Señales" en la ventana "Herramientas" (haga clic en la pestaña "Señales"):


Fig. 1. Activación de la pestaña "Señales" 

Si en la base de señales hay cambios, entonces tardarán en cargarse de tres a cinco segundos.

Hay que activar la pestaña "señales" después de conectarse a la cuenta comercial, y también en caso de conectarse a otra cuenta comercial.


2.2. Interfaz de usuario

La interfaz de la calculadora de señales incluye los siguientes elementos:


Fig. 2. Interfaz de la calculadora de señales 

  • Saldo de la cuenta comercial: saldo de la cuenta comercial conectada en el momento actual, campo editable. Después de conectar la calculadora de señales al gráfico o después de cambiar el período del gráfico en el recuadro de edición "saldo de la cuenta comercial", se mostrará el saldo de la cuenta comercial conectada actualmente. En ese recuadro solo se pueden introducir cifras del 0 al 9.
  • Divisa de la cuenta comercial, es la divisa de la cuenta comercial activa en el momento dado, la lista desplegable de las divisas más habituales. Después de conectar la calculadora de señales al gráfico, o después de modificar el periodo del gráfico, la calculadora de señales intenta encontrar en la lista el nombre de la divisa de la cuenta comercial conectada actualmente. Si no se encuentra ninguna correspondencia, entonces se elegirá la divisa por defecto: "USD".
  • Apalancamiento de la cuenta comercial, es el apalancamiento de la cuenta comercial activa en el momento dado, la lista desplegable de los apalancamientos comerciales más habituales. Después de conectar la calculadora de señales al gráfico, o después de modificar el periodo del gráfico, la calculadora de señales intenta encontrar en la lista el apalancamiento comercial de la cuenta comercial conectada actualmente. Si no se encuentra ninguna correspondencia, entonces se elegirá el apalancamiento por defecto: "1:100".
  • Carga del depósito al copiar la señal, una lista desplegable del menú del terminal "Servicio" - "Ajustes" - "Señales". Después de conectar la calculadora de señales al gráfico, o después de modificar el periodo del gráfico, la calculadora de señales intenta encontrar en la lista la carga sobre el depósito de la cuenta comercial conectada actualmente. Si no se encuentra ninguna correspondencia, entonces se elegirá la carga por defecto: "95%".
  • Recuadro de las señales disponibles en el terminal: recuadro con las señales de la pestaña del terminal "Señales". El recuadro se clasifica automáticamente en orden descendente por la columna "Coeficiente de copiado". Columnas del recuadro:
    • Columna "Crecimiento, %", es el tanto por ciento de los recursos en la cuenta como resultado de las operaciones comerciales.
    • Columna "Señal", es el nombre de la señal comercial.
    • Columna "Recursos", es la cantidad de recursos económicos en la cuenta del proveedor de la señal, teniendo en cuenta todas las obligaciones.
    • Columna "Divisa", es la divisa de la cuenta comercial del proveedor de la señal.
    • Columna "Apalancamiento", es el apalancamiento de la cuenta del proveedor de la señal.
    • Columna "Precio, $", es el precio de la señal comercial, en $.
    • Columna "Coef. de copiado", es el coeficiente de copiado que se calcula para cada señal con los ajustes seleccionados: "Saldo de la cuenta comercial", "Divisa de la cuenta comecial", "Apalancamiento de la cuenta comercial" y "Carga sobre el depósito al copiar una señal".
    • Columna "Dep. mínimo *", depósito necesario para copiar 1:1, usando el depósito a un 95%. Es decir, se trata del depósito con el cual las señales del proveedor se copiarán en su cuenta comercial con una proporción 1:1, siempre que la carga seleccionada en el depósito sea del "95%".
  • Pormenorización de los cálculos del coeficiente de copiado, es el cálculo pormenorizado del coeficiente de copiado de la señal elegida.
    • К1, es el coeficiente de proporción entre la divisa de su cuenta comercial y la de la cuenta comercial del proveedor de la señal.
    • К2, es el coeficiente de proporción entre los saldos de su cuenta comercial y de la cuenta comercial del proveedor de la señal.
    • К3, es el coeficiente de uso del depósito. Paso de los tantos por ciento a coeficiente.
    • К4, es el coeficiente de corrección de la diferencia de los apalancamientos comerciales.
    • К, es el coeficiente final. Se calcula como el producto de los coeficientes К1*К2*К3*К4.
    • Coeficiente final de copiado, es el coeficiente К redondeado por el sistema gradual.

2.3. Obtener el coeficiente de copiado

En el recuadro de señales, para cada señal en la columna "Coef. de copiado" se puede ver el coeficiente de copiado calculado para cada señal con los ajustes elegidos: "Saldo de la cuenta comercial", "Divisa de la cuenta comercial", "Apalancamiento de la cuenta comercial" y "Carga sobre el depósito al copiar una señal". 

Si lo desea, puede cambiar los ajustes: "Saldo de la cuenta comercial", "Divisa de la cuenta comercial", "Apalancamiento de la cuenta comercial" o "Carga sobre el depósito al copiar una señal". El cambio de cualquiera de estos ajustes provocará que se recalcule el coeficiente de copiado y se actualice el recuadro, y no es seguro que las señales comerciales vayan a permanecer en su sitio en el recuadro después de clasificación decreciente en la columna "Dep. mínimo*". De esta forma, es posible ver en tiempo real cómo cambia el coeficiente de copiado de la señal comercial al introducirse diferentes ajustes de la cuenta comercial.

2.4. Pormenorización del cálculo del coeficiente de copiado

Para obtener un cálculo detallado del coeficiente de copiado para una señal particular, es necesario hacer clic en el recuadro de señales, en la línea de la señal que le interese (acción 1). Después de ello, debajo del recuadro de señales se abrirá un cálculo detallado del coeficiente de copiado para la señal seleccionada (acción 2):

 

Fig. 3. Pormenorización del cálculo del coeficiente de copiado  

2.5. Imposibilidad del mapeo

Después de elegir otra divisa en la lista desplegable "Divisa de la cuenta comercial", para calcular el coeficiente de copiado, la calculadora tratará de encontrar en la ventana "Observación del mercado" el símbolo que contenga en su nombre simultáneamente la divisa de su cuenta comercial (o la divisa elegida en la lista desplegable "Divisa de la cuenta comercial"). Por ejemplo, la divisa de su cuenta comercial es "USD", y la divisa de la cuenta comercial del proveedor de la señal es "EUR". En este caso, la calculadora intentará encontrar en la ventana "Observación del mercado" el símbolo "USDEUR" y "EURUSD".  Si el símbolo no se puede localizar, en la pestaña del terminal "Expertos" se mostrará un mensaje sobre el error.

Ejemplo de mensaje sobre error de elección en la lista desplegable "Divisa de la cuenta comercial" de la divisa "SGD":

Сalculator for signals (EURUSD,M5)      Error find symbols: (Account currency SGD, Signal currency RUB)
Сalculator for signals (EURUSD,M5)      Error find symbols: (Account currency SGD, Signal currency EUR)
Сalculator for signals (EURUSD,M5)      Error find symbols: (Account currency SGD, Signal currency EUR)

Este mensaje significa que en la ventana "Observación del mercado" no hay símbolos "SGDRUB", "SGDEUR", "RUBSGD", "EURSGD". Comprobemos si esto es así: en la ventana "Observación del mercado", vamos a probar a encontrar cualquier símbolo en cuyo nombre se encuentre "SGD". Para ello, en la ventana "Observación del mercado" hay que clicar en "+ añadir":


Fig. 4. Comando "añadir" en la ventana "Observación del mercado"   

e introducir en el campo que se abra "SGD":


Fig. 5. Lista de símbolos disponibles en la ventana "Observación del mercado", en cuyos nombres se encuentra "SGD"   

Como puede ver, en la ventana "Observación del mercado" ya existe un símbolo "USDSGD" y otro "SGDJPY" se puede añadir, pero los símbolos "SGDRUB", "SGDEUR", "RUBSGD", "EURSGD", no están. 

Si el mapeo no es posible, en el recuadro de señales, en la columna "Coef. de copiado" se indicará "n/d", lo que significa "no hay datos".

Un pequeño vídeo sobre la calculadora de señales:


3. Desarrollo de la calculadora de señales

3.1. Proyectando la interfaz

Los elementos de control en la calculadora de señales se ubican de la forma siguiente:

Disposición de los elementos de control  

Fig. 6. Disposición de los elementos de control 

El archivo de inclusión "Сalculator for signals Dialog.mqh" es el responsable de la ubicación, el tamaño y la creación de los elementos de control. Los parámetros principales de los elementos de control y las sangrías se indican con la ayuda del bloque de macro substituciones:

//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
//--- indents and gaps
#define INDENT_LEFT                         (11)      // indent from left (with allowance for border width)
#define INDENT_TOP                          (11)      // indent from top (with allowance for border width)
#define CONTROLS_GAP_Y                      (5)       // gap by Y coordinate
//--- for combo boxes
#define COMBOBOX_WIDTH                      (60)      // size by X coordinate
#define COMBOBOX_HEIGHT                     (20)      // size by Y coordinate
//--- for list view
#define LIST_HEIGHT                         (102)     // size by Y coordinate
//--- for buttons
#define BUTTON_WIDTH                        (72)      // size by X coordinate
#define BUTTON_HEIGHT                       (20)      // size by Y coordinate
//--- for the indication area
#define EDIT_WIDTH                          (60)      // size by X coordinate
#define EDIT_HEIGHT                         (20)      // size by Y coordinate

De forma esquemática, los objetos de control está ubicados en el panel en cinco líneas:

  1. primera línea — Label1, Edit1, ComboBox1, Label2, ComboBox2, Label3, ComboBox2
  2. segunda línea — Label 4
  3. tercera línea — botones de Button1 a Button8 inclusive
  4. cuarta línea — nuevo elemento de control: el recuadro TableListView1
  5. quinta línea — el objeto BmpButton1, al que se asigna en calidad de archivo bmp para la representación del elemento en el estado ON, un recurso gráfico sobre la base CCanvas.
Los más importante es recordar que todos los objetos de control se ubican en el panel de diálogo (el panel principal, a su vez, se crea aquí):
//+------------------------------------------------------------------+
//| Create                                                           |
//+------------------------------------------------------------------+
bool CoSDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
//---
   m_error=true;
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
//---

Esto significa que cada objeto de control debe ser añadido después de la creación en la zona de cliente con la ayuda del método Add de la clase CDialog. Aquí vemos el aspecto que tiene con el ejemplo de la creación del objeto Label4:

//+------------------------------------------------------------------+
//| Create the "Signals" Label                                       |
//+------------------------------------------------------------------+
bool CoSDialog::CreateLabel4(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+COMBOBOX_HEIGHT+CONTROLS_GAP_Y;
   int x2=x1+100;
   int y2=y1+COMBOBOX_HEIGHT;
//--- create
   if(!m_label4.Create(m_chart_id,m_name+"Label4",m_subwin,x1,y1,x2,y2))
      return(false);
   if(!m_label4.Text(m_languages.GetText(3)))
      return(false);
   if(!Add(m_label4))
      return(false);
//--- succeed
   return(true);
  }

Primero creamos el objeto Label4:

 if(!m_label4.Create(m_chart_id,m_name+"Label4",m_subwin,x1,y1,x2,y2))
      return(false);


y antes de salir de la función, es obligatorio añadir de nuevo el objeto creado Label4 en la zona de cliente, con la ayuda del método Add:

 

 if(!Add(m_label4))
      return(false);

En general, el proceso de creación del panel y los elementos de control en este panel se puede imaginar creando el panel de la calculadora de señales en forma de esquema:

Esquema de creación de los objetos del panel

Fig. 7. Esquema de creación de los objetos del panel 

Resumiendo. En general, la creación del panel funciona según el plan siguiente:

  • se crea el propio panel (CAppDialog::Create)
  • se crean de forma secuencial los elementos de control, además, cada elemento de control se crea en el siguiente orden:
    • se crea el elemento (element_N.Create)
    • se cambian las propiedades del elemento
    • se añade obligatoriamente el elemento al panel (Add(elenemt_N))

3.2. Creamos un elemento canvas en el panel

La creación del elemento del tipo canvas tiene lugar en CoSDialog::CreateBmpButton1.

Primero de forma breve, en unos cuantos pasos:

Paso 1: creamos el recurso gráfico sin ligarlo al objeto de la gráfica (usamos el método Create de la clase CCanvas)

Paso 2: creamos el elemento de control m_bmp_button1 de la clase CBmpButton (clase del elemento simple de control basada en el objeto 'Etiqueta gráfica')

Paso 3: para el elemento de control m_bmp_button1, como archivo bmp en estado ON (método BmpOnName), establecemos nuestro elemento canvas

Paso 4: añadimos el elemento de control m_bmp_button1 al panel (método Add de la clase CDialog)

Ahora hablemos con un poco más de detalle sobre cada paso.

Paso 1

//--- create canvas
   if(!m_canvas1.Create("Canvas1",x2,y2,COLOR_FORMAT_XRGB_NOALPHA))
     {
      Print("Error creating canvas: ",GetLastError());
      return(false);
     }
   m_canvas1.FontSet("Trebuchet MS",-100,FW_THIN);
   m_canvas1.Erase(ColorToARGB(C'0xF7,0xF7,0xF7',255));
   m_canvas1.Update(true);

Preste atención a que cuando se crea el elemento canvas (m_canvas1.Create), se indican la anchura x2 y la altura y2, en esencia, son las dimensiones de la imagen, y no se modificarán:

Dimensiones del elemento canvas  

Fig. 8. Dimensiones del elemento canvas 

A continuación, se establece la fuente para el elemento canvas (m_canvas1.FontSet), el elemento canvas se rellena con el color de la zona interior de los paneles (m_canvas1.Erase) y, NECESARIAMENTE, con la representación de los cambios en la pantalla (m_canvas1.Update).

Paso 2.

//--- create
   if(!m_bmp_button1.Create(m_chart_id,m_name+"BmpButton1",m_subwin,x1,y1,x1+10,y1+10))
      return(false);

Se crear el elemento de control m_bmp_button1 con un tamaño de 10*10 píxeles. Las pequeñas dimensiones del elemento de control no importan. Aquí lo importante son las propias coordenadas x1 y y1. Se trata del punto de enlace. Es decir, si el tamaño del elemento de control se adapta al tamaño de la imagen, el ángulo con las coordenadas (x1; y1) permanecerá igual.

Paso 3.

//--- sets the name of bmp files of the control CBmpButton
   if(!m_bmp_button1.BmpOnName(m_canvas1.ResourceName()))
      return(false);

Obtenemos el nombre del recurso (m_canvas1.ResourceName()) y lo designamos como archivo bmp en estado ON (m_bmp_button1.BmpOnName). Precisamente en esta etapa, el elemento de control m_bmp_button1 se extiende, adaptándose a las dimensiones del elemento canvas.

Paso 4.

Después de crear el elemento de control, no debemos olvidar añadir este elemento al panel: 

   if(!Add(m_bmp_button1))
      return(false);

3.3. La matriz bidimensional. Clasificación

El trabajo de clasificación se realiza en el archivo "Сalculator for signals Dialog.mqh", en el método CoSDialog::InitStructurs. 

En la calculadora de señales, los datos en el recuadro están clasificados según un índice calculado: el coeficiente de copiado. Pero en el proceso de obtención del coeficiente de copiado de listas, que consta del nombre de la señal y del coeficiente de copiado calculado, no está clasificado, y tiene aproximadamente el aspecto que sigue:

Name Copy ratio
TestUSD 15.0
TradeLargeVolumes 120.0
Zeus PRO 15.0
CS Trading Co Beta Free Provider 1510.0
Mint blueberry ice cream 8.0
MT5Hedging 7.0
Forex Leos Trading 160.0
Hedge 1.0
Siksikawa 8770.0
Week H4 15.0
WGT Live Signal 45.0
Atrader 30.0
Trajecta Advisor FX491 30.0
MOsg style 6.0 

Para la clasificación se adoptó la solución sugerida por el usuario Vasiliy Sokolov: cada línea debe representarse como un cierto objeto CObject, y el recuadro al completo como un objeto CArrayObj. Ese recuadro se denomina lineal, la clase del recuadro lineal virtual (virtual, dado que el recuadro no tiene interfaz visual) se ubica en el archivo "LineTable.mqh".

Más abajo, se muestra el resultado de la clasificación en el recuadro lineal (el ejemplo se muestra para varias de las primeras líneas en el recuadro). En primer lugar, se muestran los parámetros que se insertan en el recuadro lineal (Insert : ), más abajo le sigue la iteración de todos los elementos del recuadro lineal (row #):

name rate  min_deposit
 Insert : MyCorrelation EURUSD XAUUSD  7  133134.7143
 row #0: MyCorrelation EURUSD XAUUSD  7  133134.7143
 Insert : EA microPatience AvzPrecio v6 HG 10  7  133134.7143
 row #0: MyCorrelation EURUSD XAUUSD  7  133134.7143
 row #1: EA microPatience AvzPrecio v6 HG 10  7  133134.7143
 Insert : EURUSD Daytrade  170  5482.017647
 row #0: EURUSD Daytrade  170  5482.017647
 row #1: MyCorrelation EURUSD XAUUSD  7   133134.7143
 row #2: EA microPatience AvzPrecio v6 HG 10  7  133134.7143
 Insert : Exp TickSniper PRO FULL MT5  50  18638.86
 row #0: EURUSD Daytrade  170  5482.017647
 row #1: Exp TickSniper PRO FULL MT5  50  18638.86
 row #2: MyCorrelation EURUSD XAUUSD  7  133134.7143
 row #3: EA microPatience AvzPrecio v6 HG 10  7  133134.7143
 Insert : Example1  3  310647.6667
 row #0: EURUSD Daytrade  170  5482.017647
 row #1: Exp TickSniper PRO FULL MT5  50  18638.86
 row #2: MyCorrelation EURUSD XAUUSD  7  133134.7143
 row #3: EA microPatience AvzPrecio v6 HG 10  7  133134.7143
 row #4: Example1  3  310647.6667
 Insert : Big sale  80  11649.2875
 row #0: EURUSD Daytrade  170  5482.017647
 row #1: Big sale  80  11649.2875
 row #2: Exp TickSniper PRO FULL MT5  50  18638.86
 row #3: MyCorrelation EURUSD XAUUSD  7  133134.7143
 row #4: EA microPatience AvzPrecio v6 HG 10  7  133134.7143
 row #5: Example1  3  310647.6667

En la figura se puede ver bien que después de añadirse al recuadro lineal, tiene lugar la claisifición según el campo "rate", se trata del comportamiento que precisamente necesitamos. En lo sucesivo, sabiendo que todos los elementos del recuadro están clasificados, se podrán copiar los valores en el nuevo elemento de control, el recuadro CTableListView, y estar así seguros de que los datos se presentarán de forma clasificada.

Para imprimir la clasificación paso a paso y obtener un recuadro igual, solo tendrá que comentar las líneas en el archivo "Сalculator for signals Dialog.mqh", en el método CoSDialog::InitStructurs: 

else
           {
            min_deposit=AccInfo.balance/rate*100.0;
           }
         //Print("Insert : ",name,"; ",rate,"; ",min_deposit); 
         m_table.InsertSort(new CLineTable(name,rate,min_deposit));
         //for(int m=0;m<m_table.Total();m++)
         //  {
         //   CLineTable *line=m_table.At(m);
         //   Print("row #",m,": ",line.Text(),"; ",line.Number(),"; ",line.Number1());
         //  }
        }
      else PrintFormat("Error in call of SignalBaseSelect. Error code=%d",GetLastError());
     }
//---
   return(true);
  }

3.4. Nuevo elemento de control: el recuadro CTableListView

Para representar las señales, sus características y datos calculados, crearemos un elemento visual de control: un recuadro con las posibilidad de representar varias líneas y columnas. Además, si la cantidad de líneas del recuadro es superior a la altura del recuadro, entonces deberá aparecer una barra vertical de desplazamiento. Después de las búsquedas, se decidió tomar como base un elemento de control de la clase CListView y modernizarlo significativamente.

El elemento de control recuadro CTableListView tiene dos partes: la visible, que el usuario ve físicamente y con la que contacta de forma física, y la invisible, en la que se guardan los datos de las celdas del recuadro.

La parte visible del recuadro está limitada por las dimensiones del propio elemento de control. Este está limitado por un rectángulo con coordenadas (x1; y1) y (x2; y2) y por una cantidad de columnas columns, que se establece al crear el elemento en el método Create:

   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,
                            const int y1,const int x2,const int y2,const uchar columns,const ushort &columns_size[]);

La parte visible consta de elementos de control CEdit

Construcción de la parte visible del recuadro CTableListView

Fig. 9. Construcción de la parte visible del recuadro CTableListView

Los elementos de control CEdit de la parte visible se crean y controlan con la ayuda de la matriz dinámica de punteros m_arr_rows  un objeto de la clase CArrayObj:

   CArrayObj         m_arr_rows;             // array of pointer to objects-rows (CEdit) 

(artículo sobre el uso de punteros Usando los punteros de objeto en MQL5)

La matriz de punteros m_arr_rows constituye una matrioshka de dos niveles. En el primer nivel se guardan los punteros a los objetos-línea row, a su vez, los objetos-línea row guardan los punteros a los objetos-celda (elementos CEdit) del recuadro:

Punteros a los objetos visibles

Fig. 10. Punteros a los objetos visibles 

La parte invisible también se implementa con la ayuda de la clase CArrayObj. De la parte invisible son responsables dos matrices dinámicas de punteros m_arr_rows_str m_arr_rows_val ,

   CArrayObj         m_arr_rows_str;         // array of pointer to objects-rows (CArrayString) 
   CArrayObj         m_arr_rows_val;         // array of pointer to objects-rows (CArrayLong) 

en las que se guardan el texto de las celdas y los valores, respectivamente.

La estructura de las matrices de los punteros m_arr_rows_str m_arr_rows_val es similar a la estructura de la matriz del puntero m_arr_rows, solo que en calidad de líneas intervienen las matrices de las clases CArrayStringCArrayLong, respectivamente.

3.4.1. Ejemplo del trabajo con matrices dinámicas de punteros

Analizamos el trabajo con matrices dinámicas de punteros tomando como ejemplo la creación del objeto recuadro:

//+------------------------------------------------------------------+
//| Create a control                                                 |
//+------------------------------------------------------------------+
bool CTableListView::Create(const long chart,const string name,const int subwin,const int x1,
                            const int y1,const int x2,const int y2,const uchar columns,const ushort &columns_size[])
  {
   m_columns=columns;
   ArrayResize(m_columns_size,m_columns);
   if(ArraySize(columns_size)!=m_columns)
      return(false);
   ArrayCopy(m_columns_size,columns_size,0,0,WHOLE_ARRAY);
   m_columns_size[0]-=1;
   m_columns_size[m_columns-1]-=1;
   int y=y2;
//--- if the number of visible rows is previously determined, adjust the vertical size
   if(!TotalView((y2-y1)/m_item_height))
      y=m_item_height+y1+2*CONTROLS_BORDER_WIDTH;
//--- check the number of visible rows
   if(m_total_view<1)
      return(false);
//--- call method of the parent class
   if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y))
      return(false);
//--- set up
   if(!m_background.ColorBackground(CONTROLS_LIST_COLOR_BG))
      return(false);
   if(!m_background.ColorBorder(CONTROLS_LIST_COLOR_BORDER))
      return(false);
//--- create dependent controls
   CArrayObj *m_arr_cells;
   for(int i=0;i<m_total_view;i++)
     {
      m_arr_cells=new CArrayObj;
      if(CheckPointer(m_arr_cells)==POINTER_INVALID)
         return(false);
      for(int j=0;j<m_columns;j++)
        {
         CEdit *m_cell;
         m_cell=new CEdit;
         if(CheckPointer(m_cell)==POINTER_INVALID)
            return(false);
         m_arr_cells.Add(m_cell);
        }
      m_arr_rows.Add(m_arr_cells);
     }
//---
   for(int i=0;i<m_total_view;i++)
     {
      if(!CreateRow(i))
         return(false);
      if(m_height_variable && i>0)
        {
         // m_rows[i].Hide(); ///
         CArrayObj *m_arr_cells_i=m_arr_rows.At(i);
         if(CheckPointer(m_arr_cells_i)==POINTER_INVALID)
            return(false);
         for(int j=0;j<m_arr_cells_i.Total();j++)
           {
            CEdit *m_cell=m_arr_cells_i.At(j);
            if(CheckPointer(m_cell)==POINTER_INVALID)
               return(false);
            if(!m_cell.Hide())
               return(false);
           }
        }
     }
//--- succeed
   return(true);
  }

En el bloque de código

//--- if the number of visible rows is previously determined, adjust the vertical size
   if(!TotalView((y2-y1)/m_item_height))
      y=m_item_height+y1+2*CONTROLS_BORDER_WIDTH;

tiene lugar la llamada de TotalView, donde se calcula la cantidad de líneas visibles. Esta cantidad se guarda en la variable m_total_view.

Después en el ciclo for(int i=0;i<m_total_view;i++) se crean las líneas m_arr_cells, y en el ciclo for(int j=0;j<m_columns;j++) las líneas se rellenan con las celdas m_cell:

//--- create dependent controls
   CArrayObj *m_arr_cells;
   for(int i=0;i<m_total_view;i++)
     {
      m_arr_cells=new CArrayObj;
      if(CheckPointer(m_arr_cells)==POINTER_INVALID)
         return(false);
      for(int j=0;j<m_columns;j++)
        {
         CEdit *m_cell;
         m_cell=new CEdit;
         if(CheckPointer(m_cell)==POINTER_INVALID)
            return(false);
         m_arr_cells.Add(m_cell);
        }
      m_arr_rows.Add(m_arr_cells);
     }
//---

Tras pasar por completo el ciclo for(int j=0;j<m_columns;j++) cada línea rellenada se añade a la matriz principal m_arr_rows:

      m_arr_rows.Add(m_arr_cells);

De esta forma, tras pasar por completo el ciclo for(int i=0;i<m_total_view;i++) ya tenemos una matriz de punteros rellenada m_arr_rows, que según su estructura corresponde a la parte visible del recuadro (ver fig. 9).

Después de rellenar la matriz de punteros en el segundo ciclo for(int i=0;i<m_total_view;i++) tiene lugar la visualización del recuadro (creación de la parte visible del recuadro), usando la llamada a CreateRow:

//---
   for(int i=0;i<m_total_view;i++)
     {
      if(!CreateRow(i))
         return(false);
      .
      .
      .
     }
//--- succeed
   return(true);

Método CreateRow:

//+------------------------------------------------------------------+
//| Create "row"                                                     |
//+------------------------------------------------------------------+
bool CTableListView::CreateRow(const int index)
  {
   .
   .
   .
//--- create
   CArrayObj *m_arr_cells=m_arr_rows.At(index);
   if(CheckPointer(m_arr_cells)==POINTER_INVALID)
      return(false);
   for(int i=0;i<m_arr_cells.Total();i++)
     {
      CEdit *m_cell=m_arr_cells.At(i);
      if(CheckPointer(m_cell)==POINTER_INVALID)
         return(false);
      x1+=x2;
      x2=m_columns_size[i];
      if(!m_cell.Create(m_chart_id,m_name+"_"+IntegerToString(index)+"_"+IntegerToString(i),
         m_subwin,x1,y1,x1+x2,y2))
         return(false);
      if(!m_cell.Text(""))
         return(false);
      if(!m_cell.ReadOnly(true))
         return(false);
      if(!Add(m_cell))
         return(false);
     }
   .
   .
   .
   return(true);
  }

En el bloque de código obtenemos de la matriz de punteros m_arr_rows el puntero al elemento m_arr_cells (el elemento m_arr_cells  tiene el tipo CArrayObj), que se encuentra en la posición index. El elemento m_arr_cells es precisamente la línea del recuadro row (ver fig. 10). Usamos el método At de la clase CArrayObj:

   .
//--- create
   CArrayObj *m_arr_cells=m_arr_rows.At(index);
   if(CheckPointer(m_arr_cells)==POINTER_INVALID)
      return(false);
   for(int i=0;i<m_arr_cells.Total();i++)

Más adelante, en el ciclo for(int i=0;i<m_arr_cells.Total();i++) trabajamos ya con el elemento m_arr_cells (matriz de punteros): obtenemos de la matriz de punteros m_arr_cells el puntero al elemento m_cell (el elemento m_cell tiene el tipo CEdit),  que se encuentra en la posición i:

      CEdit *m_cell=m_arr_cells.At(i);
      if(CheckPointer(m_cell)==POINTER_INVALID)
         return(false);

A continuación, creamos las celdas (elementos de control de la clase CEdit) con nombre único:

      if(!m_cell.Create(m_chart_id,m_name+"_"+IntegerToString(index)+"_"+IntegerToString(i),
         m_subwin,x1,y1,x1+x2,y2))
         return(false);

cambiamos algunas de las propiedades de los elementos de control creados (borramos todo el texto del elemento de control y hacemos que el elemento de control sea no editable):

      if(!m_cell.Text(""))
         return(false);
      if(!m_cell.ReadOnly(true))
         return(false);

Y por último, aunque sea un paso no menos importante, agregamos a nuestro panel el elemento de control creado de nuevo:

      if(!Add(m_cell))
         return(false);
     }

Conclusión

Espero que encuentre útil la calculadora de señales al elegir una señal, y lo más importante, que la calculadora le ayude a ver cómo va a cambiar el coeficiente de copiado, si va a cambiar (en la calculadora) el tamaño del depósito y/o el apalancamiento de su cuenta comercial.