En esta tercera y última parte del artículo realizaremos un estudio de caso siguiendo la metodología ya descrita de las series sintéticas e implementaremos un algoritmo para NinjaTrader que nos permitirá automatizar el proceso de evaluación.
10.- Estudio de caso: Aplicación del
método al sistema SandBox
Seguidamente haremos una evaluación completa del sistema intradiario aplicado al futuro del S&P500 (ES) que ya vimos en el artículo “Selección de parámetros y enfoques multiescenario”. Este sistema es de tipo micro-tendencial y puede posicionarse largo o corto con una cadencia operativa media de 120 operaciones al año. Veamos paso a paso cómo realizar una evaluación del tipo MSS:
Esta sería la configuración de partida:
A medida que avanza el proceso, el resultado de las iteraciones
se irá almacenado automáticamente en una hoja Excel que nos servirá para
analizar la enorme cantidad de datos que genera este procedimiento.
El primer elemento importante a evaluar es la distribución del PnL y la estadística descriptiva de todos los escenarios simulados. En el caso que nos ocupa estos serían los resultados en la secuencia combinada de las 1000 series:
Como podemos ver, las operaciones extremas son bastante
infrecuentes y los datos con frecuencias relativas altas (>100.000) aparecen agrupados en el rango ±1.000$.
La media de la distribución es el dato más relevante y nos da un BMO (beneficio
medio por operación) sintético de 34,81$.
Estos son los datos de la estadística descriptiva, de los que nos interesan sobre todo la media y la desviación estándar:
El segundo elemento importante de este análisis multi-hilo será la distribución del Net Profit y del Drawdown máximo. Y estos son los resultados que obtenemos en las 1000 series:
Como podemos ver en este ejemplo los datos también aparecen muy agrupados, tanto para el Net Profit como el DDm.:
El tercer elemento es el análisis de los resultados agrupados por percentiles. Para ello construimos una tabla con los principales ratios y los resultados que obtenemos para ellos en cada percentil (1/0) en saltos de 0,05. El criterio de ordenación en este caso es el Net Profit pero podríamos haber elegido cualquier otro ratio diana:
Los percentiles extremos
normalmente se descartan. Las referencias clave serían P 0,9-0,95 para los
escenarios de máximo rendimiento, P 0,45-0,55 para los escenarios situados en
la media y P 0,1-0,05 para los escenarios de mínimo rendimiento.
En el siguiente gráfico mostramos las curvas más representativas de daca percentil y los DD asociados:
Como vemos, estas curvas nos
muestran los caminos posibles para un determinado umbral de variabilidad en la
transformación aplicada a los precios.
11.- Combinación de los métodos de las permutaciones paramétricas (MPP) y de las series sintéticas (MSS).
Una tercera forma muy completa de
evaluar el sistema es combinando los métodos MPP y MSS El procedimiento
consiste en aleatorizar las horquillas paramétricas de las zonas robustas en
series sintéticas generadas con el método anteriormente descrito. Se trata de
un procedimiento de cómputo intensivo que puede consumir muchas horas, incluso
con los ordenadores más potentes, pero permite simular muchos más escenarios y
obtener una diversidad mayor.
Los pasos a seguir son:
1.- Establecer las horquillas paramétricas para el MPP. En el caso del sistema que nos ocupa serían:
2.- Configurar el optimizador
para trabajar sobre las horquillas. Lógicamente no vamos a poder realizar las
cientos de millones de combinaciones del punto anterior, por lo que será
necesario reprogramar el optimizador para que, dado un número de iteraciones
expresado en el parámetro “iteracion” (pongamos unas 5.000), genere ese número
de combinaciones paramétricas al azar siempre dentro de la horquilla.
En este caso la modificación del
código es trivial, se trata sólo del método Iterate() en el que para cada
parámetro que tenga horquilla se trata al azar en cada iteración, dentro de
nuestro optimizador personalizado OHLCDespl:
private
void Iterate(int index)
{
…
var random = new
Random(Guid.NewGuid().GetHashCode());
//solo optimizara sobre
el parametro iteracion
if(p.Name!="Iteracion"){
if
(index == Parameters.Count - 1) return;
Iterate(index + 1);
return;
}
//aqui
sólo entra si es el parámetro iteración
for (int i = 0; p.Min + i *
p.Increment <= p.Max + p.Increment / 1000000; i++)
{
p.Value = p.Min + i * p.Increment;
/*se prepara combinación
paramétrica al azar*/
for(int j=0;j
p_aux=Parameters[j];
if(p_aux.Name=="Iteracion")
continue;
if(p_aux.Max==p_aux.Min){
//no tiene horquilla
p_aux.Value=p_aux.Min;
continue;
}
if
(p.ParameterType != typeof(int) && p.ParameterType != typeof(double))
//se
ignoran los no numéricos
continue;
int
indice=random.Next(1,(int)((p_aux.Max-p_aux.Min)/p_aux.Increment)+1);
p_aux.Value=p_aux.Min+(indice*p_aux.Increment);
}
//ejecuta
iteracion con combinación paramétrica al azar
RunIteration(null, null);
}
}
Ahora ya podemos especificar las horquillas sin problema, especificando el número de iteraciones en el parámetro, sabiendo que se limitará a ese número de combinaciones paramétricas (todo el resto de configuración queda igual):
3.- Elección de hardware
adecuado. Aunque no lo parezca tanto a priori, este proceso dará como resultado
una hoja de cálculo de cientos de megabytes de tamaño y necesitará una enorme
capacidad de cómputo y memoria.
Los recursos necesarios en
NinjaTrader para que se exporten bien los resultados serán ligeramente superiores
a 64Gbytes de RAM (poco frecuente en equipos comerciales) y un conjunto de
procesadores bastante respetable si queremos resultados en un orden de magnitud
de horas (y no días). En esto último está el principal problema: en apartados
anteriores se ha visto que se sacrificó el soporte multithread para evitar
problemas de concurrencia, por lo que idealmente se necesita un solo procesador
enorme de uno o dos núcleos cosa que no existe en el mercado, amén de que
aunque existiera, no se va a realizar un gran desembolso económico sólo para
estos experimentos.
La solución moderna a este
problema pasa por el uso un servidor cloud, que virtualmente se crea, se usa y se
destruye bajo demanda, con la capacidad arbitraria que se requiera y cuyo uso
se abona por horas.
Esta es una solución utilizada
frecuentemente en procesos industriales que requieren enormes capacidades de
cómputo muy especializadas durante escasos períodos de tiempo, por ejemplo para
Big Data, para renderización gráfica en producciones cinematográficas (ejemplo
de estudios de renderización FuseFX) o para procesamiento
masivo de documentos (ejemplo “TimesMachine”
de New York Times), ofreciendo procesamiento intensivo de uso esporádico a
un coste contenido y predecible.
El proveedor estrella en este
ámbito es Amazon Web Services (AWS) que tiene decenas de opciones para utilizar
servidores virtuales bajo demanda con configuraciones
hardware personalizadas de lo más variopinto (denominadas “instancias”)
desde máquinas normales hasta supercomputadores de 128 procesadores y 2
Terabytes de RAM.
En nuestro caso, se trata de
elegir una instancia con más de 64 Gbytes y que tenga un gran procesador de uno
o dos núcleos. Desde 2018 en AWS es
posible virtualizar muchos procesadores en uno con uno o dos núcleos,
debido a la existencia de aplicaciones de cómputo intensivo cuyo modelo de
licenciamiento se paga por número de procesador y núcleos, lo que permite un
gran ahorro económico. En nuestro caso nos viene de perlas por la carencia de multithreading.
Así las cosas, se ha elegido una
instancia r5.4xlarge que dispone de 128Gbytes de RAM, 16 procesadores Intel
Xeon Platinum 8000 a 3,1 GHz. configurables como un único procesador virtual,
cuya ejecución en la región más económica (Ohio) cuesta aproximadamente 1$ la
hora.
Este coste puede abaratarse
considerablemente si no hay excesiva prisa y se acude al mercado de instancias spot,
con un funcionamiento parecido al de un mercado de valores (pero para el
cómputo) donde se especifica un precio máximo -al estilo de una orden limitada-
y nuestra instancia se ejecutará siempre y cuando no haya una gran demanda.
Por ejemplo y para el caso que nos ocupa, se ha lanzado la instancia en la región Ohio (us-east2) en un fin de semana especificando como precio máximo el doble de la demanda instantánea proporcionada por AWS (current price 0,17$/h), con lo que nos aseguramos un funcionamiento continuado de al menos 48h -más que suficiente- a un precio medio de unos 0,20$ por hora de procesamiento:
Así las cosas, se pudo realizar
el procesamiento que nos ocupa en 29 horas (incluida la exportación a Excel, la
cual es lenta y complicada de acelerar) con un coste teórico de 5 euros frente
a los más de 3000 euros que costaría adquirir un equipo de inferiores
características. Además AWS tiene diferentes programas de desarrollo y crédito
promocional por lo que ni siquiera se tuvo que hacer frente a este coste.
4.- Analizar los datos una vez obtenida la Excel, siguiendo los pasos y fijándonos en los elementos ya descritos en el apartado anterior. Este es el gráfico resultante de un proceso combinado en el que se simularon 5.000 escenarios:
1.- El talón de Aquiles de muchos sistemas es la falta
de datos históricos suficientemente largos para hacer una evaluación fiable y
que contemple la mayor cantidad de escenarios posibles. Este es el caso del
clásico procedimiento walk-forward y
sus variantes. Para resolver este problema hemos propuesto la implementación de
modelos multiescenario que, a pesar de ser más complejos y difíciles de
implementar, podrían generar estimaciones más realistas, completas y precisas
de la estrategia a evaluar.
2.- El método de las series sintéticas permite
simular escenarios introduciendo pequeños cambios aleatorios en las formaciones
de precios. Estos pequeños cambios se realizan barra a barra y de manera
secuencial, considerando la volatilidad próxima, con lo que se consigue un
número ilimitado de series derivadas de la original con similares propiedades
estadísticas y sin alterar las dependencias, patrones horarios y efectos de
estacionalidad.
3.- La implementación del método MSS en plataformas
de trading diseñadas para programar y evaluar estrategias permite realizar un
backtest multi-hilo y evaluar la estrategia en un número elevado de series
alternativas.
4.- Los métodos de las permutaciones paramétricas y
de las series sintéticas se pueden combinar, generando mayor diversidad en un
número virtualmente ilimitado de escenarios alternativos. De este modo se
obtienen estimaciones más realistas y se detectan riesgos latentes que
posiblemente con otros métodos de evaluación podrían pasar desapercibidos.
5.- Desde el punto de vista técnico de la
implementación NinjaTrader no es muy eficaz computacionalmente y sus
posibilidades de programación personalizada no están muy adaptadas a los fines
perseguidos. Sería conveniente estudiar otras plataformas que sí permitan
añadir de forma sencilla una capa de procesamiento intermedio entre la serie de
datos real y el código de la estrategia de una manera más óptima y reproducible,
o bien que permita a la estrategia su ejecución sobre grandes conjuntos de
series alteradas generadas de forma fija previamente.
6.- Las automatizaciones de código en Excel, aunque
sin duda son una gran herramienta y ayuda, siempre presentan problemas de
rendimiento difíciles de solucionar, amén de que pueden no estar disponibles
para su programación en todas las plataformas. En aras de optimizar recursos y
aumentar la compatibilidad, cabría la posibilidad de exportar los resultados
detallados en un formato csv que posteriormente se trasladase manual o
semiautomáticamente a una plantilla Excel preparada que realiza todo el
análisis y graficación.
7.- En todo caso, las necesidades computacionales pueden ser mucho más importantes de lo habitual y por tanto el uso de la computación en nube con equipos de gran potencia y pago por uso resulta muy interesante para disponer de una gran capacidad de cómputo esporádica en un corto espacio de tiempo a un coste predecible.
José Luis Gil y Andrés A. García
©TradingSys.org, 2019