2013-01-31 26 views
18

Aşağıda her nokta için Bollinger Bantlarını hesaplamak için C# yöntemimi görebilirsiniz (hareketli ortalama, yukarı bant, aşağı bant).Hareketli Standart Sapma Nasıl Hesaplanır

Gördüğünüz gibi, bu yöntem hareketli ortalama kullanarak hareketli standart sapmayı hesaplamak için döngüleri 2 kullanır. Son n periyotları boyunca hareketli ortalamayı hesaplamak için ek bir döngü içermekteydi. Bu, döngünün başlangıcında total_average için yeni nokta değerini ekleyerek ve i-n noktası değerini döngü sonunda kaldırarak kaldırabilirim.

Sorum şu: Temel olarak kalan iç döngü, hareketli ortalama ile yönetilen şekilde giderebilir miyim?

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"]; 
      } 
     } 
    } 

cevap

20

Cevap evet, yapabilirsin. 80'li yılların ortalarında, bir süreç izleme ve kontrol uygulaması için FORTRAN'da böyle bir algoritma (muhtemelen orijinal değil) geliştirdim. Ne yazık ki, bu 25 yıl önce oldu ve ben tam formülleri hatırlamıyorum, ama teknik sadece doğrusal olanlar yerine ikinci dereceden hesaplamalar ile, ortalama hareketli için bir uzantısı oldu.

Kodunuza biraz baktıktan sonra, o zaman nasıl yaptığımı anlayabileceğimi düşünüyorum. İçinizdeki döngü ortalama başlangıçta sahip Değerlerin bir Sum vardı gerektiğini hemen aynı şekilde Kareler bir Sum ?:

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

yapıyor nasıl fark ettiniz mi? Tek iki farklılık, düzen (1 yerine 2 güç) ve karesini çizmeden önce her değerin ortalamasını çıkarmanızdır. Şimdi bu ayrılmaz görünebilir, ama aslında onlar ayrılabilir:

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

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

olduğunu

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

olur

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

olduğu da hangi

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

Şimdi ilk terim sadece bir kareler toplamıdır, aynı şekilde, ortalama değerler için toplamı yaptığınız gibi. Son terim (k^2*n), period'un yalnızca ortalama kareleridir. Sonucu, zaman dilimine böldüğünüz için, ekstra döngü olmadan yeni ortalama kareyi ekleyebilirsiniz.

Son olarak, ikinci dönem (SUM(-2*v[i]) * k) 'de, SUM(v[i]) = total = k*n beri sonra bu içine değiştirebilirsiniz:

-2 * k * k * n 

ya da sadece -2*k^2*n, hangi -2 ortalama karesi kez, dönemin kez (n) tekrar ayrılmıştır.Yani nihai kombine formüldür:

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

veya

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

(bu geçerliliğini kontrol etmeyi unutmayın kafamın üst kapalı türetmek am beri) Ve birleşmeyle kodunuza şu gibi bir şey görünmelidir:

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); 
     } 
    } 
} 
+4

Çok teşekkürler! Bu konuda kör bakıyordum. - = Math.pow (veri TOTAL_SQUARES: Yalnızca sonunda TOTAL_SQUARES azaltmak unuttum.Değerler [i - periyot + 1] ["yakın"], 2); – ChrisW

+2

http://www.johndcook.com/blog/standard_deviation/ – odyth

+0

@odyth Güzel referans! Bunun Knuth’ta olduğunu fark etmemiştim. Bunu 80'lerde yazmamdan birkaç yıl önce TAoCP okumuştum ve şimdi bilinçaltında intihal ettiğimi merak ediyorum. – RBarryYoung

1

Buna çok benzeyen bir şey için, commons-math (ve bu kütüphaneye katkıda bulundu!) Kullanıyorum. Bu açık kaynak, C# için mağaza satın alınan pasta olarak kolay olmalı (sıfırdan bir pasta yapmayı denediniz mi?). Şuna bak: http://commons.apache.org/math/api-3.1.1/index.html. StandardDeviation sınıfları var. Kasabaya gitmek!

+0

Teşekkürler ama bunun gibi basit bir hesaplama için matematik kütüphanesini gerek olduğunu sanmıyorum. – ChrisW

+0

Rica ederim! Üzgünüm aradığın cevabım yoktu. Kesinlikle kütüphanenin tamamını göstermeyi önermek istemedim! Sadece birkaç yüz satırlık olması gereken en az gerekli kod. Apache'nin bu kod üzerinde hangi yasal/telif hakkı kısıtlamalarına sahip olduğunu bilmediğimi, dolayısıyla bunu kontrol etmeniz gerektiğini unutmayın. Eğer bunun peşinden, buradan [link] (http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/descriptive olduğunu /moment/StandardDeviation.java?revision=1416643&view=markup). Yani bu + Varyans + FastMath? –

25

Squ toplamını hesaplayan yaklaşımlarla ilgili sorun ares, bu ve toplamların karesinin oldukça büyük olması ve farklarının hesaplanması very large error'u getirebilir, bu yüzden daha iyi bir şey düşünelim. Bunun neden gerekli olduğu konusunda, Algorithms for computing variance ve John Cook'un Theoretical explanation for numerical results numaralı URL makalesi hakkındaki Wikipedia makalesine bakın. İlk olarak, stddev'i varyansa odaklanalım. Varyansa sahip olduğumuzda, stddev sadece varyansın kareköküdür.

bir dizi x adlandırılan veri varsayalım; n boyutlu bir pencerenin tek tek yuvarlanması, x[0]'un değerinin kaldırılması ve x[n]'un değerinin eklenmesi olarak düşünülebilir. Sırasıyla, x[0]..x[n-1] ve x[1]..x[n]'un ortalamalarını µ ve µ ’ile gösterelim. x[0]..x[n-1] ve x[1]..x[n] varyansları arasındaki fark, sonra bazı terimleri dışarı iptal ve (a²-b²) = (a+b)(a-b) uyguladığını:

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) 

nedenle varyans iyidir kareler toplamını, muhafaza etmek gerekmez şey tarafından rahatsız edilir sayısal doğruluk için.

Sen düzgün bir algoritma (Welford's method) ile başlangıçta bir kez ortalama ve varyansını hesaplayabilirsiniz.

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) 
+1

Bunun için teşekkürler. CLR için C# 'daki bir uygulamanın temeli olarak kullandım. Pratikte, "new_Var" ın bir _very_ küçük negatif sayı olduğu ve sqrt'un başarısız olduğu şekilde güncelleyebileceğinizi keşfettim. Bu durum için değeri sıfıra sınırlamak için bir “if” girdim. Fikir değil, ama kararlı. Bu, benim penceremdeki her değerin aynı değere sahip olduğu zaman ortaya çıktı (birinin bunu denemek ve yeniden üretmek istemesi durumunda 20'lik bir pencere boyutu ve söz konusu değer 0,5'di). –

0

En önemli bilgiler zaten yukarıda verilmiştir --- ama belki bu hala geçerli: Bundan sonra, her zaman böyle ortalamasını ve varyansını güncellemek başka x[n] pencereye x[0] bir değer değiştirmek zorunda genel menfaat

ortalama ve standart sapmayı hareketli hesaplamak için minik bir Java kütüphanesi

burada mevcuttur: https://github.com/tools4j/meanvar

uygulama yukarıda belirtilen Welford en yöntemin bir varyantında dayanmaktadır. Değer pencerelerini taşımak için kullanılabilen değerleri çıkarma ve değiştirme yöntemleri türetilmiştir.

İlgili konular