Cualquier pregunta de novato, para no saturar el foro. Profesionales, no pasen de largo. En ninguna parte sin ti - 6. - página 641

 
simpleton:

¿Por qué emular un error?

Error - es para señalar que, por alguna razón relacionada con las limitaciones/fallas del sistema, el algoritmo no pudo ser ejecutado y el resultado obtenido con algunas (limitadas, por supuesto, pero - ) garantías. La función FillAndPrint() muestra de forma elocuente lo que significa una situación de error y lo que no. Cuando se produce un error, ni siquiera intenta imprimir el resultado. Si no hay ningún error, el resultado es fiable. Así es como debe construirse la lógica del error/no error.

Aquí hay que modificar el algoritmo: hay que aplicar un filtro adicional.

Así es como debe hacerse:

Primero, "filtramos" por tipos de objetos y parámetros, seleccionando sólo los objetos que necesitamos de entre todos los disponibles, y luego aplicamos un filtro adicional. Es más o menos como lo haría una persona. Eso es lo que haría una persona, ¿no?

Para cada una de estas pequeñas subtareas, es deseable una función separada.

No debe haber números en las expresiones, excepto en casos muy especiales, por ejemplo si se necesita duplicar y está en la naturaleza del algoritmo hacerlo. Entonces el número 2 se puede utilizar directamente en las expresiones. Y en otros casos muy raros.

En otros casos, se debe utilizar la mnemotecnia. En primer lugar, mejoran en gran medida la comprensión de lo que ocurre en un lugar determinado y, por tanto, ayudan a reducir la posibilidad de cometer un error. Y en segundo lugar, el valor en sí está definido en un solo lugar y es fácil cambiarlo si es necesario, y será imposible cometer un error en comparación con el caso en el que el número se utiliza en el algoritmo más de una vez, y sin usar mnemónicos hay que fijar los números en varios lugares del algoritmo.

Resultado de la carrera:

No se encuentra ni un solo objeto. Aumente los valores de ambas mnemotecnias 10 veces hasta llegar a 36000 (10 horas), y ejecute de nuevo:

Una tendencia ya ha "pasado" el filtro. Ahora vamos a restablecer el valor del primer mnemónico a 3600 y ejecutar:

Se puede observar que ambas tendencias han "pasado" el filtro. Por cierto, recomiendo depurar todas las ramas (partes) del programa de esa manera, en lugar de una sola rama.

Para ayudar a formalizarlo de alguna manera, intentaré explicarlo de esta manera. El programa es aparentemente como un plan.

Cada elemento del plan principal puede desglosarse en elementos más pequeños del plan secundario. Los más pequeños en otros aún más pequeños. Las partidas de los subplanes más pequeños se ejecutan directamente.

Cada plan, subplano e incluso los subplanos más pequeños corresponden a funciones del programa. Los elementos de los subplanos más pequeños corresponden a funciones "finales" que sólo llaman a funciones del sistema o que incluso no las llaman en absoluto, por ejemplo, AddValue() o DiffInSecs() son ejemplos de los comentados anteriormente. Los elementos del subplano de arriba corresponden a las funciones que llaman a las funciones que implementan los elementos del subplano de abajo. En las comentadas anteriormente, son MassTrendNumber(), AddValueIfFound(), AddValueIfFiltered(). Las funciones de "bajo nivel" no deben llamar a funciones de "alto nivel", y las funciones de "alto nivel" básicamente no deben saltar varios niveles hacia abajo, es decir, sólo deben llamar a funciones básicamente del nivel inferior. Esta norma es mucho más estricta para los "niveles bajos" que para los "niveles altos".

Intenta construir tus programas organizando las acciones en ellos como funciones (cortas) enlazadas por este tipo de estructura de árbol, en el sentido de quién llama a quién.

Este programa tiene un árbol degenerado: una rama que se "ramifica" varias veces. Y se "ramifica" no en dos pequeñas ramas sino en una. Pero se puede ver el punto de que las funciones de "alto nivel" llaman sistemáticamente a las de "bajo nivel". En esta modificación, he insertado un nivel más en esta estructura, una "rama no ramificada" más - AddValueIfFiltered().

Pego el código listo.

La tarea: buscar líneas de tendencia(OBJ_TREND) y registrar los valores de los precios relativos a la barra actual en un array. Filtrado contra la existencia de parámetros de tiempo del objeto (OBJ_TREND).

#property strict

/******************************************************************************/
bool AddValue(double &array[], const double value) {
  const int size = ArraySize(array);

  if (ArrayResize(array, size + 1) != size + 1) {
    return false; // Ошибка, значение не может быть добавлено к массиву
  }

  array[size] = value; //записываем
  return true; // Нет ошибки, значение добавлено к массиву
}

/******************************************************************************/
bool AddValueIfFound(double &array[], const string name) {
  const int type = ObjectType(name);

  if (type == OBJ_TREND) {
    switch ((color)ObjectGet(name, OBJPROP_COLOR)) { // Тип color допустимо использовать в switch
    case Goldenrod:
    case Gainsboro:
    case White:
      if (!AddValueIfFiltered(array, name)) { // Пропускаем через фильтр
        return false;
      }
    }
  }

  return true; // Нет ошибки, значение, если найдено, добавлено к массиву
}
/******************************************************************************/
bool MassTrendNumber(double &array[], const bool buy) { // Поиск значения цены трендовой линии, текущего бара, запись в массив. Два массива: masS и masB
  const string subname = (buy ? "uptrendline" : "downtrendline"); // существует два названия трендовых линий, первое и второе

  if (ArrayResize(array, 0) != 0) {
    return false; // Ошибка, массив не может быть заполнен достоверно
  }

  for (int i = 0, limit = ObjectsTotal(OBJ_TREND); i < limit+2; i++) {
    if (!AddValueIfFound(array, subname + IntegerToString(i))) {
      return false; // Ошибка, массив, если и заполнен, то недостоверно
    }
  }
 
  return true; // Нет ошибки, массив заполнен достоверно
}
/******************************************************************************/
long DiffInSecs(const datetime dt1, const datetime dt2) {
  return dt1 - dt2;
}
/******************************************************************************/
bool AddValueIfFiltered(double &array[], const string name) {
#define MIN_SECS_BETWEEN_PRICE1_AND_PRICE2 3600
#define MAX_SECS_AFTER_PRICE2              3600

  const datetime dt1 = (datetime)ObjectGet(name, OBJPROP_TIME1);
  const datetime dt2 = (datetime)ObjectGet(name, OBJPROP_TIME2);
  const datetime dt = TimeCurrent();
  
  Print("name = ", name,// ", dt = ", dt, ", dt1 = ", dt1,"\n", 
  " DiffInSecs = ", DiffInSecs(dt,dt2)," DiffInSecs = ", DiffInSecs(dt2,dt1));

   if( DiffInSecs(dt,dt2)>MAX_SECS_AFTER_PRICE2 && DiffInSecs(dt2,dt1)> MIN_SECS_BETWEEN_PRICE1_AND_PRICE2){
    if (!AddValue(array, ObjectGetValueByShift(name, 1))) { // Пытаемся добавить
      return false; // Ошибка, значение не добавлено
    }
  }

  return true; // Нет ошибки, значение, если удовлетворило условию фильтра, добавлено к массиву
}

/******************************************************************************/
void FillAndPrint(double &array[], const bool buy) {
  if (MassTrendNumber(array, buy)) {
    const int limit = ArraySize(array);

    Print("Найдено объектов: ", limit);

    for (int i = 0; i < limit; i++) {
      Print("Price[", i, "] = ", DoubleToStr(array[i], Digits));
    }
  } else {
    Print("Чёрт!");
  }
}

/******************************************************************************/
void OnTick()

//=============================================================================================
//====================================== Линии тренда =========================================
//=============================================================================================
 double masS[]; double masB[];

  Print("Sell:");
  FillAndPrint(masS, false);

  Print("Buy:");
  FillAndPrint(masB, true);
 simpletonСпасибо вам большое, вы за пестовали меня на ощущения правильного кода!) (Правда я немногое понял))))
 
evillive:

Ahora tengo 4 dígitos, en ewardollar a 1 lote 1 punto cuesta 10 dólares y siempre ha sido así. Para los cruces el coste será de 8 a 16, la fórmula es un poco más complicada allí.

Por ejemplo, para la libra euro marketinfo ha devuelto 16,984, el tipo de cambio libra-dólar = 1,6984, es decir, 1 punto de la libra euro vale 1 libra, multiplicado por el valor en puntos de la libra-dólar, que siempre es 10,0 (100000 * 0,0001 = 10,0 o 100000 * 0,00010 = 10,0 - lo que uno quiera).


Todos estos cálculos son correctos sólo si su cuenta está en dólares:

En este caso, para xUSD (EURUSD, GBPUSD, etc.) tickvalue = lote*punto = 100000*0,0001 = 10,0

para USDh (USDCHF, USDJPY etc) tickvalue = lote*punto/Oferta = 100000*0.01/101.93=9.8107

para xUSD/yUSD (EURGBP) tickvalue = Bid(yUSD)*lot*point = 1.6980*100000*0.0001 = 16.98

para xUSD/USDy (EURJPY) tickvalue = lote*punto/Bid(USDy) = 100000*0.01/101.91 = 9.8126


¡Algo que has estropeado! Se tomó el tiempo de buscar en el código, las expresiones seleccionadas, y mirar:

  double TV = MarketInfo(Symbol(),MODE_TICKVALUE); 
  string sTV = DoubleToStr(TV,4); 
  Comment("TV ",sTV); //sTV = 1.0/Bid

No puede ser más sencillo. No 10, 16, etc.

 
evillive:

Ahora tengo 4 dígitos, en ewardollar a 1 lote 1 punto cuesta 10 dólares y siempre ha sido así. Para los cruces el coste será de 8 a 16, la fórmula es un poco más complicada allí.

Por ejemplo, para la libra euro marketinfo ha devuelto 16,984, el tipo de cambio libra-dólar = 1,6984, es decir, 1 punto de la libra euro vale 1 libra, multiplicado por el valor en puntos de la libra-dólar, que siempre es 10,0 (100000 * 0,0001 = 10,0 o 100000 * 0,00010 = 10,0 - lo que uno quiera).


Todos estos cálculos son correctos sólo si su cuenta está en dólares:

En este caso, para xUSD (EURUSD, GBPUSD, etc.) tickvalue = lote*punto = 100000*0,0001 = 10,0

para USDx (USDCHF, USDJPY etc) tickvalue = lote*punto/Oferta = 100000*0.01/101.93 = 9.8107

para xUSD/yUSD (EURGBP) tickvalue = Bid(yUSD)*lot*point = 1.6980*100000*0.0001 = 16.98

para los cruces xUSD/USDy (EURJPY) tickvalue = lote*punto/Bid(USDy) = 100000*0.01/101.91=9.8126




¡Esto está mal! El valor de una cotización no importa.Y el valor de un tick mínimo debe calcularse a partir del precio actual. ¡Lo que equivale a TICK_VALUE! Arriba hay un ejemplo de mi código.
 
borilunad:

borilunad:

¡Esto está mal! El valor de una cotización es irrelevante. ¡Y el valor de un min.tick debe ser calculado a partir del precio actual! ¡Lo que equivale a TICK_VALUE! Arriba hay un ejemplo de mi código.

¿Qué tiene de malo? Marketinfo devuelve los mismos valores que las fórmulas que di anteriormente. Estas fórmulas no las he inventado yo, las utiliza el terminal para calcular el TickValue))

Está claro que es más conveniente tomar el valor de Marketinfo, pero él pedía fórmulas o métodos de cálculo.

Y sobre el valor escribí antes, que no importa, porque en cuentas de 5 díg itos un punto = 10 pips, y es el mismo punto de 4 dígitos.

 
evillive:

¿Qué tiene de malo? Marketinfo devuelve los mismos valores que las fórmulas que di anteriormente. Estas fórmulas no las he inventado yo, las utiliza el terminal para calcular el TickValue).

Está claro que es más conveniente tomar el valor de Marketinfo, pero él pedía fórmulas o métodos de cálculo.

Y escribí antes sobre la signitud, que no importa, porque en cuentas de 5 dígitos un punto = 10 pips, y este es el mismo punto de 4 dígitos.


Eso es lo que quiero decir conMarketInfo(Symbol(),MODE_TICKVALUE) =1.0/Bid;Quizás sólo para el Eurodólar, ¡no lo pulverizo en otros!
 
borilunad:

A eso me refiero conMarketInfo(Symbol(),MODE_TICKVALUE) =1.0/Bid;Quizás, sólo para el Euro, ¡no para otros!

Esto es exactamente lo que ocurre con el eurodólar, según la definición que se da en la ayuda

MODE_TICKVALUE

16

Cambio mínimo del precio del valor en la moneda del depósito


Y significa multiplicar

PUNTO_MODE

11

Tamaño del punto en la moneda de cotización. Para el símbolo actual se almacena en la variable predefinida Punto


por

MODE_LOTSIZE

15

Tamaño del contrato en la moneda base del instrumento


Porsupuesto, si su cuenta está en euros, debe utilizar el euro como moneda base, pero para los operadores que tienen una cuenta en dólares (lo más frecuente), las fórmulas anteriores son válidas. Dado que los pares principales y más negociados se basan en el dólar estadounidense, estas fórmulas son las más utilizadas.

 
evillive:

Esto es exactamente erróneo, basándose en la definición dada en la ayuda

MODE_TICKVALUE

16

Cambio mínimo del precio del símbolo en la moneda del depósito


Significa que este valor debe multiplicarse por

PUNTO_MODE

11

Tamaño del punto en la moneda de cotización. Para el símbolo actual se almacena en la variable predefinida Punto


en

MODE_LOTSIZE

15

Tamaño del contrato en la moneda base del instrumento


Por supuesto, si su cuenta está en euros, debería usar euros, pero la mayoría de los operadores tienen una cuenta en dólares.


Bueno, entonces, tengo un caso especial, pero para mí, que vivo en la zona del euro, ¡es más conveniente realizar todos los cálculos en euros!
 

Señores, por favor, denme un ejemplo de código para el siguiente indicador. No consigo averiguar cuántos topes se necesitan, qué tipo de cartografía y dónde y qué propiedades deben prescribirse para ellos.

El indicador es el siguiente:

1 Las barras se conectan al menos cada tres y adyacentes. La línea es roja.

2 Tramos de barra conectan los máximos de cada 5 barras y adyacentes. La línea es azul.

Lo principal: los segmentos no se cruzan de ninguna manera. El principio y el final de cada segmento son independientes de los demás.

El indicador calcula los valores del principio y el final de cada segmento. Deben colorearse de forma diferente en función de las condiciones.

Este es el aspecto que debería tener, a grandes rasgos


 

Y otra pregunta.

¿Es normal que no pueda trabajar con el indicador en modo de depuración?

Cuando el programa llega al punto de parada, el terminal MT4 se cuelga y la ventana se vuelve blanca (en HP) por lo que es imposible ver lo que se dibuja en el gráfico

 
Top2n:

Aquí está el código listo.

Tarea: Buscar líneas de tendencia (OBJ_TREND), registrar los valores de los precios relativos a la barra actual en un array. Con filtrado respecto a la existencia de parámetros temporales del objeto (OBJ_TREND).

simpleton: ¡Muchasgracias, mehiciste sentir el código correcto!) (Aunque no entendí mucho))))

Si practicas, la comprensión llegará, cada vez más. Requiere concentración y atención. Cuando el algoritmo del programa se unta en una gran función, es difícil realizarlo con concentración y atención: se forman demasiados enlaces. Pero si un programa se divide en partes funcionalmente completas (pequeñas funciones), es mucho más fácil hacerlo para cada pequeña función por separado. Y así en cada nivel de función. Por cierto:

   if( DiffInSecs(dt,dt2)>MAX_SECS_AFTER_PRICE2 && DiffInSecs(dt2,dt1)> MIN_SECS_BETWEEN_PRICE1_AND_PRICE2){
    if (!AddValue(array, ObjectGetValueByShift(name, 1))) { // Пытаемся добавить
      return false; // Ошибка, значение не добавлено
    }
  }
Debo haber nombrado mal el mnemónico MAX_SECS_AFTER_PRICE2 (porque al principio entendí así que la condición debía ser inversa), el significado debería ser probablemente MIN_SECS_AFTER_PRICE2, es decir, el mínimo permitido, no el máximo.