visual varianza tipica tabla poblacional moda mediana frecuencias estandar distribucion desviacion como calcular c# algorithm finance moving-average standard-deviation

c# - varianza - Cómo calcular eficientemente una desviación estándar en movimiento



desviacion estandar formula c# (4)

El problema con los enfoques que calculan la suma de los cuadrados es que puede aumentar bastante y el cuadrado de las sumas, y el cálculo de su diferencia puede introducir un error muy grande , así que pensemos en algo mejor. Para saber por qué es necesario, consulte el artículo de Wikipedia sobre Algoritmos para calcular la varianza y John Cook en Explicación teórica para resultados numéricos .

Primero, en lugar de calcular el estándar, centrémonos en la varianza. Una vez que tenemos la varianza, stddev es solo la raíz cuadrada de la varianza.

Supongamos que los datos están en una matriz llamada x ; se puede pensar que mover una ventana de tamaño n por uno elimina el valor de x[0] y agrega el valor de x[n] . Denotemos los promedios de x[0]..x[n-1] y x[1]..x[n] por µ y µ ''respectivamente. La diferencia entre las variaciones de x[0]..x[n-1] y x[1]..x[n] es, después de cancelar algunos términos y aplicar (a²-b²) = (a+b)(ab) :

Var[x[1],..,x[n]] - Var[x[0],..,x[n-1]] = (/sum_1^n x[i]² - n µ’²)/(n-1) - (/sum_0^{n-1} x[i]² - n µ²)/(n-1) = (x[n]² - x[0]² - n(µ’² - µ²))/(n-1) = (x[n]-µ’ + x[0]-µ)(x[n]-x[0])/(n-1)

Por lo tanto, la variación se ve perturbada por algo que no requiere que mantengas la suma de los cuadrados, lo que es mejor para la precisión numérica.

Puede calcular la media y la varianza una vez al principio con un algoritmo adecuado ( método de Welford ). Después de eso, cada vez que tenga que reemplazar un valor en la ventana x[0] por otra x[n] , actualice el promedio y la varianza de esta manera:

new_Avg = Avg + (x[n]-x[0])/n new_Var = Var + (x[n]-new_Avg + x[0]-Avg)(x[n] - x[0])/(n-1) new_StdDev = sqrt(new_Var)

A continuación puede ver mi método de C # para calcular las Bandas de Bollinger para cada punto (promedio móvil, banda superior, banda inferior).

Como puede ver, este método utiliza 2 para los bucles para calcular la desviación estándar de movimiento utilizando la media móvil. Solía ​​contener un bucle adicional para calcular la media móvil en los últimos n períodos. Este podría eliminarlo agregando el nuevo valor de punto a total_average al comienzo del bucle y eliminando el valor de punto i - n al final del bucle.

Mi pregunta ahora es básicamente: ¿Puedo eliminar el bucle interno restante de una manera similar a la que manejé con la media móvil?

public static void AddBollingerBands(SortedList<DateTime, Dictionary<string, double>> data, int period, int factor) { double total_average = 0; for (int i = 0; i < data.Count(); i++) { total_average += data.Values[i]["close"]; if (i >= period - 1) { double total_bollinger = 0; double average = total_average / period; for (int x = i; x > (i - period); x--) { total_bollinger += Math.Pow(data.Values[x]["close"] - average, 2); } double stdev = Math.Sqrt(total_bollinger / period); data.Values[i]["bollinger_average"] = average; data.Values[i]["bollinger_top"] = average + factor * stdev; data.Values[i]["bollinger_bottom"] = average - factor * stdev; total_average -= data.Values[i - period + 1]["close"]; } } }


He usado los matemáticos comunes (¡y he contribuido a esa biblioteca!) Para algo muy similar a esto. Es de código abierto, la transferencia a C # debería ser fácil como un pastel comprado en la tienda (¿has intentado hacer un pastel desde cero?). Échale un vistazo: http://commons.apache.org/math/api-3.1.1/index.html . Tienen una clase estándar de evolución. ¡Ir a la ciudad!


La información más importante ya se ha dado anteriormente, pero quizás esto todavía sea de interés general.

Una pequeña biblioteca de Java para calcular el promedio móvil y la desviación estándar está disponible aquí: https://github.com/tools4j/meanvar

La implementación se basa en una variante del método de Welford mencionado anteriormente. Se han derivado métodos para eliminar y reemplazar valores que se pueden usar para mover ventanas de valores.


La respuesta es sí, usted puede. A mediados de los 80, desarrollé un algoritmo de este tipo (probablemente no original) en FORTRAN para una aplicación de control y monitoreo de procesos. Desafortunadamente, eso fue hace más de 25 años y no recuerdo las fórmulas exactas, pero la técnica fue una extensión de la de promedios móviles, con cálculos de segundo orden en lugar de solo lineales.

Después de revisar su código, creo que puedo analizar cómo lo hice en aquel entonces. Observe cómo su bucle interno está haciendo una suma de cuadrados:

for (int x = i; x > (i - period); x--) { total_bollinger += Math.Pow(data.Values[x]["close"] - average, 2); }

de la misma manera que su promedio debe haber tenido originalmente una suma de valores? Las dos únicas diferencias son el orden (su potencia 2 en lugar de 1) y que está restando el promedio de cada valor antes de cuadrarlo. Ahora eso puede parecer inseparable, pero en realidad se pueden separar:

SUM(i=1; n){ (v[i] - k)^2 }

es

SUM(i=1..n){v[i]^2 -2*v[i]*k + k^2}

que se convierte

SUM(i=1..n){v[i]^2 -2*v[i]*k} + k^2*n

cual es

SUM(i=1..n){v[i]^2} + SUM(i=1..n){-2*v[i]*k} + k^2*n

cual es también

SUM(i=1..n){v[i]^2} + SUM(i=1..n){-2*v[i]}*k + k^2*n

Ahora el primer término es solo una suma de cuadrados, lo manejas de la misma manera que haces la suma de los valores para el promedio. El último término ( k^2*n ) es solo el cuadrado al cuadrado promedio del period . De todos modos, ya que se divide el resultado por el período, solo puede agregar el nuevo cuadrado promedio sin el bucle adicional.

Finalmente, en el segundo término ( SUM(-2*v[i]) * k ), ya que SUM(v[i]) = total = k*n , puede cambiarlo a este:

-2 * k * k * n

o simplemente -2*k^2*n , que es -2 veces el cuadrado al cuadrado, una vez que el período ( n ) se divide nuevamente. Así que la fórmula final combinada es:

SUM(i=1..n){v[i]^2} - n*k^2

o

SUM(i=1..n){values[i]^2} - period*(average^2)

(Asegúrate de verificar la validez de esto, ya que lo estoy sacando de la cabeza)

Y la incorporación a tu código debería tener este aspecto:

public static void AddBollingerBands(ref SortedList<DateTime, Dictionary<string, double>> data, int period, int factor) { double total_average = 0; double total_squares = 0; for (int i = 0; i < data.Count(); i++) { total_average += data.Values[i]["close"]; total_squares += Math.Pow(data.Values[i]["close"], 2); if (i >= period - 1) { double total_bollinger = 0; double average = total_average / period; double stdev = Math.Sqrt((total_squares - Math.Pow(total_average,2)/period) / period); data.Values[i]["bollinger_average"] = average; data.Values[i]["bollinger_top"] = average + factor * stdev; data.Values[i]["bollinger_bottom"] = average - factor * stdev; total_average -= data.Values[i - period + 1]["close"]; total_squares -= Math.Pow(data.Values[i - period + 1]["close"], 2); } } }