Está perdiendo oportunidades comerciales:
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Registro
Entrada
Usted acepta la política del sitio web y las condiciones de uso
Si no tiene cuenta de usuario, regístrese
El probador tiene su propia lista de herramientas y necesita ser generado (preferiblemente hecho al inicializar el EA).
El código era aproximado (copiado de dos piezas), pero tus comentarios son correctos.
Aquí está la versión corregida:
He añadido un par de llamadas a Print() para que quede claro cómo funciona realmente:
Ahora funciona correctamente. Pero con una advertencia: en las condiciones que se dan actualmente. Si se amplían en el futuro, este código empezará a cometer errores en algunos casos bajo ciertas condiciones. Lo explicaré a continuación.
En realidad, tuve que hacer algunas investigaciones y obtuve resultados muy interesantes como resultado. Pero hablemos de ellos uno por uno.
Lo primero que me salta a la vista es esto: ¿por qué he tenido que bailar tanto con NormalizeDouble()? ¿Qué hace NormalizeDoubel()? Vincula un valor libre a la rejilla. Por ejemplo, en este fragmento de código
NormalizeDouble() toma como parámetro lot_pure (valor libre, es decir, el calculado por el margen libre y el margen necesario para 1 lote sin ningún redondeo y otras vinculaciones) y da el valor, vinculado al valor más cercano de la cuadrícula con inicio en 0 y paso 0,01.
Aquí es importante tener en cuenta: al nodo más cercano de la red, ¡incluido el más grande!
¿Para qué sirve esta ligadura en este lugar del código? ¿Y por qué a la cuadrícula de 0,01 y no a, por ejemplo, 0,001?
Por cierto, podemos ver que el resultado marcado con CO en el registro (la primera línea del fragmento mostrado) ha dado lugar al valor aumentado.
Además, sabemos que todas las funciones comerciales que aceptan el número de lotes como uno de los parámetros, requieren que este valor esté ligado a la rejilla: minvol + N * stepvol, donde N es un número entero desde 0 hasta el valor de una parte entera de la expresión (maxvol - minvol) / stepvol. En consecuencia, el valor del lote libre obtenido en este fragmento:
debe estar ligado al nodo más cercano de la cuadrícula especificada: minvol + N * stepvol. Esto significa que primero hay que restar minvol del valor de lotes antes de dividir por stepvol (para obtener ese entero N), y después de multiplicar por N, añadir minvol. Pero inmediatamente se divide por stepvol, asumiendo implícitamente que stepvol es un divisor de minvol, es decir, que cabe un número entero de veces, porque sólo si se cumple esta condición se puede "simplificar" de esta manera y no obtener efectos secundarios:
De nuevo se utiliza NormalizeDouble(), esta vez para enlazar con una cuadrícula con inicio en 0 y paso en 1, es decir, con números enteros. Los parámetros de unión de la rejilla son correctos, pero la herramienta de ajuste es un poco desafortunada: se une al nodo más cercano de la rejilla, incluyendo un nodo más grande si resulta estar más cerca. Y en nuestro caso llevará a la posterior elaboración obligatoria del código de corrección. ¿Por qué no utilizar aquí una maravillosa herramienta de vinculación a "una cuadrícula de enteros" utilizando en lugar de llamar a NormalizeDouble() un casting a tipo entero que no incremente el valor que se está casteando, sino que sólo lo decremente al entero más cercano si es necesario, es decir, lo que necesitamos?
Pero aquí se produce un artefacto más interesante que se comprueba en la segunda línea del fragmento citado marcado con JG. Resulta que la expresión "0,1 * NormalizeDouble(7,8 / 0,1)" da el resultado 7,800000000000001, ¡lo que hace que el código corrector funcione! ¿Por qué se necesita un código que funciona tan mal que hay que añadirle un corrector?
Está claro que el código de vinculación a la parrilla de valores de lote aceptables debe ser sustituido por uno mejor.
Por supuesto, podemos dejar este código también - después de todo, la parte de corrección del código, si es que funciona. Aquí la tercera línea del registro lo demuestra: el resultado vuelve justo al final. Pero este código, por otra parte, es un indicador de la profesionalidad y la calidad de sus creadores. Incluyendo la calidad del código de la plataforma MT5. Y la prueba de ello la voy a dar yo, porque me he topado con dos bichos como resultado de mi investigación.
Por cierto, veamos de nuevo el código de vinculación inicial del valor calculado de lot_pure y el código de corrección:
En ambos casos hay una vinculación a la cuadrícula con el paso 0,01. ¿Por qué esta cuadrícula? Porque hay que enlazar con la cuadrícula minvol + N * stepvol que tiene un stepvol. ¿Qué pasará cuando en el futuro tengamos tanto el valor mínimo del lote como el stepvol de 0,001?Es muy simple - el código dará resultados erróneos en los casos en que en el proceso de vinculación a la red con el paso 0,01 el valor libre cambia en el valor más de 0,001. Esta es la advertencia que mencioné al principio.
En caso de "redondear hacia arriba" en más de 0,001, se devolverán los valores del lote con un margen libre insuficiente para abrir la posición, mientras que en caso de "redondear hacia abajo" en la misma cantidad - valores subestimados o 0, si el valor libre está dentro del rango de 0,001 - 0,004999...
Es decir, el código contiene un error potencial para el futuro. Es una cuestión de profesionalidad de los desarrolladores y de calidad de su código.
Ahora, teniendo en cuenta lo que he encontrado, voy a sugerir mi propia variante de la función:
Hay varios casos, en relación con el valor de los lotes (almacenado en mi tmp), calculado pero aún no vinculado a una cuadrícula de valores válidos. Llamemos al valor de la cuadrícula discretizado.
1. El caso cuando tmp < minvol. En este caso, la desigualdad también se mantendrá después de la discretización de tmp, porque el proceso de discretización sólo implica la reducción del valor calculado (de lo contrario, no hay suficiente margen libre, ya que el valor calculado es el máximo valor posible para la cantidad dada de margen libre).
Por lo tanto, este caso puede eliminarse en una fase temprana, antes del muestreo.
2. El caso cuando tmp > maxvol. En este caso, la limitación no es el margen libre, sino el número máximo de lotes aceptado por las funciones de negociación. En este caso, sólo devuelve el valor de maxvol.
Para devolver simplemente el valor de maxvol, no es necesario el muestreo de tmp, por lo que este caso también se corta antes del código de muestreo.
3. El caso cuando minvol <= tmp <= maxvol. En este caso es necesario discretizar, pero el valor discretizado queda dentro de una desigualdad para este caso, es decir, no es necesario corregir nada después de la discretización.
El código de muestreo es sencillo y eficaz:
Aquí, la expresión "(tmp - minvol) / stepvol" calcula el mismo número N (el parámetro de la cuadrícula de anclaje), pero con una parte fraccionaria. Como aquí se cumple la desigualdad minvol <= tmp (caso 3), se garantiza que el valor calculado es no negativo. A continuación, lanzamos explícitamente el valor calculado a un valor de tipo ulong. Es ulong porque se garantiza que el valor calculado es no negativo.
Durante la conversión a tipo entero, se descarta la parte fraccionaria del tipo real. No se redondea a la unidad más cercana, sino que se descarta la parte fraccionaria, lo que garantiza que no se incremente el valor máximo de los lotes que permite el margen libre. Eso es exactamente lo que necesitamos.
Dado que se obtiene el valor entero de N, entonces el valor discretizado máximo del número de lotes, que permite el margen libre, se obtiene de forma estándar (es decir, el siguiente entero en la parrilla de valores discretizados de los lotes no permitirá el margen libre, mientras que el N obtenido seguirá permitiendo el margen libre): "minvol + stepvol * N".
Quiero destacar un punto bastante importante. La cuestión es que los números de tipo double pueden tomar valores máximos hasta aproximadamente 1,8e308, mientras que los números de tipo ulong - sólo alrededor de 1,8e19 (es sólo una entrada por conveniencia, la constante 1,8e19 no es de tipo ulong).
¿Qué pasa si el valor de la expresión "(tmp - minvol) / stepvol" supera 1,8e19? En este caso, durante la conversión al tipo ulong, se producirá un "corte" - el valor será el resto de la división entera del valor de la expresión por ULONG_MAX.
Si los números no fueran tan grandes, en términos de MQL5, se vería como "X % ULONG_MAX", donde X es un entero igual a "(tmp - minvol) / stepvol".
Este no es un caso típico, pero ¿por qué dejar errores en el código? Además, las funciones de la librería MQL5 no son de fiar, pueden devolver cualquier tontería (voy a dar una prueba de ello).
Para los casos en los que el valor de la expresión "tmp / stepvol" no se ajusta a 1,8e19, hemos introducido a propósito una comprobación (la última línea de la condición if):
tmp < ULONG_MAX * stepvolPor supuesto, puede escribir "tmp / stepvol < (double)ULONG_MAX" pero, en primer lugar, intento evitar las operaciones de división cuando no hay una necesidad explícita y, en segundo lugar, tendría que realizar una conversión de tipo explícita ya que la constante ULONG_MAX es de tipo ulong, Cuando se comparan los operandos, no se lanzan implícitamente a un tipo superior (al menos es así en C/C++), y en el tercero - no habría encontrado un bonito error en el propio lenguaje, ni siquiera en las funciones de la biblioteca - el error no es que en el ADN, pero, literalmente, en las moléculas y átomos de MQL5.
El operando izquierdo de la operación de comparación es tmp y tiene el tipo double mientras que el operando derecho es la expresión "ULONG_MAX * stepvol" y también tiene el tipo double.
Esta expresión tiene dos operandos, uno de tipo ulong y otro de tipo double. Según las reglas de la conversión implícita de tipos, primero el operando del tipo inferior se convierte en el operando del tipo superior, se ejecuta la operación y el resultado se convierte en el operando del tipo superior. El tipo double es "más antiguo" que ulong, por eso el valor ULONG_MAX de ulong es implícitamente fundido a double, se realiza la operación y el resultado es de tipo double.
Sin embargo, aquí hay un error que, por cierto, aparece no siempre sino sólo en algunos casos, incluyendo éste, y el error consiste en que el resultado de la expresión "ULONG_MAX * stepvol" es sólo el valor de stepvol.
Por lo tanto, la función que estoy mostrando no funciona y no funcionará hasta que los desarrolladores de MetaQuotes arreglen este error.
Para empezar a utilizar esta función ahora, hay que aprovechar la peculiaridad del fallo: desaparece si se realiza una conversión de tipo explícita:
Volviendo a la comprobación descrita: garantiza que el valor de la expresión "tmp / stepvol" no excederá de ULONG_MAX. Pero el código de muestreo utiliza la expresión "(tmp - minvol) / stepvol".
El valor de esta expresión tampoco superará ULONG_MAX porque las comprobaciones anteriores aseguran que minvol > 0 y tmp >= minvol, es decir, tmp - minvol < tmp.
Por lo tanto, la garantía de no exceder ULOMG_MAX también se aplica a la expresión "(tmp - minvol) / stepvol".
Por lo general, una de las principales diferencias entre un profesional y un profano es que un profesional puede al menos garantizar algo, mientras que un profano...
He desmontado los dos fallos encontrados en el otropost, a la vez que he aclarado lo que MetaQuotes hacía y no conseguía hacer.
Для чего в этом месте кода выполняется эта привязка? И почему именно к сетке 0.01, а не к, скажем, 0.001?
En el sistema, el lote mínimo = 0,01
Notas:
Hablo sólo por mí (pero si ves tu reflejo, no eres el único).
A lo largo de los últimos meses de persecución de errores, he desarrollado el hábito de considerar primero un programa que no funciona como un error en MetaTrader.
Por qué es así, es sólo un patrón bien probado, si algo no funciona, entonces es un error y dejar que las campanas de alarma.
Ejemplo: Encontré un error, envié una solicitud a servicedesk, escribieron un código de verificación, pero nada.
Volví a solicitarlo y, en espera de una respuesta, descubrí mi torpeza.
El resultado es que me avergüenza haber distraído a la gente en el acto.
Pero analizando el flujo de mensajes entiendo que la masa de gente, aunque sea inteligente, sigue sometida a la psicología de la multitud.
Si hay fallos, escribiré un fallo y dejaré que Renat resuelva mi código y señale mi error.
Entiendo que la tolerancia no permite decir: sí eres un imbécil, tu código está torcido.
Pero no se puede ir tan lejos, y prolongar aún más todo el personal MQ pronto se dedicará a que se sientan en los códigos de otras personas en la contemplación lúgubre "pero ¿por qué necesitamos todo", mientras que el campeonato se acerca, y allí e ir a las cuentas reales no están muy lejos.
Termino, mi lema de hoy es "Si vas a publicar un error, comprueba si el problema está en tus manos".
Nueva construcción - nuevos problemas. Expert, que ha funcionado bien en el 306 después de la compilación en el 314 (compilación sin errores), da error en el tester:
2010.08.21 17:03:36 Core 1 desconectado2010.08.21 17:03:36 Core 1 tester parado porque OnInit falló
2010.08.21 17:03:36 Core 1 2010.01.04 00:00:00 Violación de acceso leída a 0x0000000000000014
2010.08.21 17:03:36 Core 1 2010.01.04 00:00:00 Balance=10000.00 Equite=10000.00 Profit=0.00
2010.08.21 17:03:36 Core 1 2010.01.04 01.04 00:00:00 PriceChannel_multi_Ch_Timer Asesor Experto comenzó a trabajar en 2010.01.04 00:00 en el gráfico EURUSD para el período H1
También se descarga en la vida real. Parece que la fuente de error es una línea
Sustituyéndolo por un par de líneas
string curSymbol=TradeSymbols[i]; m_symbol[j].Name(curSymbol);devolvió el statu quo al Asesor Experto.
¿Cuál es el problema?
Por cierto, el código compilado en la última compilación, funciona bien en esta también.
¿Cuál es el problema?
Por cierto, el código compilado en la última compilación también funciona bien en esta.
Lote mínimo = 0,01
Notas:
Ahora mismo el lote mínimo del sistema = 0,01. ¿Pero qué pasará dentro de un año? ¿En dos años?
1) ¿Qué condición es correcta? ¿Cuál es entonces la fórmula correcta? Digamos que, para minvol = 0,15 y stepvol = 0,1 - ¿cuáles serían los primeros valores de lote válidos? a) 0,15, 0,25, 0,35... ? б) 0.15, 0.2, 0.3... ? в) ... ? He asumido que es la opción a.
2. Me cambié a ulong por una razón - tengo el derecho de elegir el tipo con la gama más amplia, por lo que sería suficiente para la mayor gama de casos posibles, porque tales funciones son ladrillos muy básicos. Y el hecho de que me haya encontrado con un error no significa que haya sido yo quien haya creado los problemas. :) Razonamiento escribió más para otros para dejar claro a la gama más amplia posible - tenemos aquí no una correspondencia personal.
3. La sustitución no es complicada, sólo hay que ahorrar, para no crear variables de un solo uso. Y se ha comprobado y verificado que la variable se pasa por referencia cuando se llama a una función como máximo una vez, de forma que se evitan posibles errores por ello. Si a algunos les molesta, pueden crear una variable para cada valor transferido (incluso uno intermedio, como el precio de venta), como has hecho tú. Este punto no es importante.
Mucho más importante es el mecanismo de vinculación a la parrilla de valores admisibles, que, además, no requiere corrección, y que garantiza que no se produzcan fallos en diferentes casos no muy típicos, manteniendo la máxima simplicidad posible.
La premisa es que el bloque de construcción básico debe ser tan robusto y versátil como sea posible - entonces toda la casa probablemente incluso sobrevivirá a un terremoto.
Hablo sólo por mí (pero si ves tu reflejo, no eres el único).
Durante los últimos meses de la carrera por los bugs, he desarrollado el hábito de considerar un bug en MetaTrader como un bug en primer lugar.
Por qué, sólo un patrón bien establecido, si algo no funciona, entonces es un error y dejar que las campanas de alarma.
El hecho de que los bichos de MQL5 y MQL5 se parezcan mucho a los suyos juega un papel importante aquí. Y hay muchos errores en MQL5.
Si MQL5 tuviera bastantes menos fallos y no fueran tan simples, sería mucho más difícil confundirlos.
Ya han empezado a pensar en la posibilidad de iniciar el Campeonato, y ha llegado el momento de que empiecen a trabajar en las cuentas reales de trading.
Para terminar, el lema de hoy es "Si vas a publicar un error, comprueba si el problema está en tus manos".
El hecho de que el Campeonato para Asesores Expertos escritos SOLO en MQL5 es una apuesta clara en el momento en que se anunció la decisión. Pero la dirección de EA tiene su propia visión. Ellos mismos lo han decidido. Nadie interfirió en su decisión. Y qué más da que el campeonato esté a la vuelta de la esquina, se han buscado la vida.
Aquí es fácil: hay que hacer un trabajo de localización del fallo: empezar a eliminar del código todo lo que no afecta al fallo. Por último, obtendrá una especie de ejemplo de prueba, que es bastante pequeño pero que demuestra principalmente el error. Esto ya no será "el código de otra persona" sino "el código que demuestra el error MQL5".
He escrito un script para comprobar la función OrderCalcMargin(). La función devuelve cero para algunos símbolos.
Esto es probablemente para aquellos símbolos que no están en MarketWatch, ya que se dice que SymbolName es para SymbolName:
NombreSímbolo
Devuelve el nombre del símbolo especificado.
cadenaSymbolName(
intpos,// número de la lista
bool selected// true - sólo símbolos en MarketWatch
);
Parámetros
pos
[en] Número de símbolo en orden.
seleccionado
[en] Modo de consulta. Si es verdadero, el símbolo se toma de la lista de seleccionados en MarketWatch. Si el valor es falso, el símbolo se toma de la lista común.
Valor devuelto
Valor de tipo cadena con nombre de símbolo.