Chcę obliczyć wartość EMA (Exponential Moving Average) w PHP. Ive starał się z następującego kodu, ale daje mi 500 błąd. PHP: EMA funkcja obliczania trader-ema Próbowałem przez długi czas Googling, ale nie otrzymuję żadnej pomocy na ten temat w PHP. Tak więc nie mam pojęcia, co należy zrobić, aby obliczyć wartość EMA. Edit-1: Zainstalowane rozszerzenia Zainstalowałem wszystkie niezbędne rozszerzenia, Teraz otrzymuję dane wyjściowe. Ale wydaje się, że nie daje właściwego wyniku. Myślę, że funkcja PHP do obliczania EMA nie działa poprawnie. Każda pomoc w tym będzie bardzo mile widziana. Próbuję pobrać ostatnią EMA dużego zbioru danych (15000 wartości). Jest to algorytm bardzo zasobożerny, ponieważ każda wartość zależy od poprzedniej. Oto mój kod: Co już zrobiłem: Izoluj k, więc nie jest obliczany 10000 razy Zachowaj tylko najnowszą obliczoną EMA i nie zatrzymuj wszystkich w tablicy używając for () zamiast foreach () tablica danych nie ma kluczy jest to podstawowa tablica To pozwoliło mi zredukować czas wykonywania z 2000ms do około 500ms dla 15000 wartości Co nie działało: Użyj SplFixedArray (), to ogolone tylko 10ms wykonując 1 000 000 wartości Użyj rozszerzenia PHPTrader. to zwraca tablicę zawierającą wszystkie EMA zamiast tylko najnowszego, a jej wolniejsze pisanie i uruchamianie tego samego algorytmu w C i uruchamianie go ponad 2 000 000 wartości zajmuje tylko 13 ms. Oczywiście, używanie skompilowanego, niższego poziomu języka wydaje się pomagać P Gdzie czy powinienem odejść stąd Kod ostatecznie będzie działał na Ubuntu, więc jaki język powinienem wybrać Czy PHP będzie w stanie zadzwonić i przekazać tak ogromny argument do skryptu zadanego 11 lipca 14 o 19:21 Jasne wdrożenie z rozszerzeniem daje ci znaczący wzrost. Dodatkowo rachunek może być poprawiony sam w sobie i ten przyrost możesz dodać w dowolnym wybranym języku. Łatwo zauważyć, że lastEMA można obliczyć w następujący sposób: Można to przepisać w następujący sposób, aby wyjąć z pętli jak najwięcej: Aby wyjaśnić ekstrakcję k, myślę, że w poprzednim sformułowaniu jest tak, jakby wszystkie oryginalne nieprzetworzone dane są mnożone przez k, więc praktycznie można zamiast tego pomnożyć wynik końcowy. Zauważ, że przepisane w ten sposób, masz 2 operacje w pętli zamiast 3 (dokładniej w pętli są też i inkrementacja, i porównanie z wielkością i przypisaniem wartości lastEMA), więc w ten sposób możesz spodziewać się dodatkowej przyspieszenie w zakresie od 16 do 33. Ponadto istnieją inne ulepszenia, które można rozważyć przynajmniej w niektórych okolicznościach: Weź pod uwagę tylko ostatnie wartości Pierwsze wartości są mnożone kilka razy przez k1m 1 - k, więc ich wkład może być mały lub nawet pod precyzją zmiennoprzecinkową (lub dopuszczalnym błędem). Pomysł ten jest szczególnie przydatny, jeśli można założyć, że starsze dane mają ten sam rząd wielkości co nowsze, ponieważ jeśli bierze się pod uwagę tylko ostatnie wartości, błąd, który popełniasz, to err EMAofdiscardeddata (1-k) n. Jeśli zatem rząd wielkości jest zasadniczo taki sam, możemy powiedzieć, że popełniony błąd względny jest relerr err lastEMA EMAofdiscardeddata (1-k) n lastEMA, który jest prawie równy prostemu (1-k) n. Przy założeniu, że lastEMA jest prawie równe EMAofdiscardeddata: Powiedzmy, że możesz zaakceptować względny relerr błędów, możesz bezpiecznie rozważyć tylko ostatnie n wartości, gdzie (1-k) n lt relerr. Oznacza, że możesz wstępnie obliczyć (przed pętlą) n log (relerr) log (1-k) i obliczyć wszystko tylko z uwzględnieniem ostatnich n wartości. Jeśli zbiór danych jest bardzo duży, może to dać sensowne przyspieszenie. Rozważmy, że dla 64-bitowych liczb zmiennoprzecinkowych mamy względną precyzję (związaną z mantysą), która wynosi 2-53 (około 1,1 e-16 i tylko 2-24 5,96 e-8 dla 32-bitowych liczb zmiennoprzecinkowych), więc nie można uzyskać lepiej niż ten względny błąd, więc w zasadzie nigdy nie powinieneś mieć przewagi w obliczaniu więcej niż n log (1.1e-16) wartości log (1-k). dać przykład, jeśli zakres 2000, a następnie n log (1.1e-16) log (1-22001) 36746. Myślę, że to jest interesujące wiedzieć, że dodatkowe obliczenia gubią się w zaokrągleniach, które są bezużyteczne, lepiej nie robić. teraz jeden przykład dla przypadku, w którym można zaakceptować błąd względny większy niż zmiennoprzecinkowa precyzja relerr 1ppm 1e-6 0.00001 6 znaczących cyfr dziesiętnych, które masz n log (1.1e-16) log (1-22001) 13815 Myślę, że jest całkiem mała liczba w porównaniu z ostatnimi liczbami próbek, więc w takich przypadkach przyspieszenie może być ewidentne (zakładam, że zakres 2000 jest znaczący lub wysoki dla twojej aplikacji, ale nie mogę tego wiedzieć). tylko kilka liczb, ponieważ nie wiem, jakie są twoje typowe dane: relerr 1e-3 range 2000 n 6907 relerr 1e-3 range 200 n 691 relerr 1e-3 range 20 n 69 relerr 1e-6 range 2000 n 13815 relerr 1e 6 zakres 200 n 1381 relerr zakres 1e-6 20 n 138 Jeśli założenie lastEMA prawie równe EMAofdiscardeddata nie może być podejmowane, sprawy są mniej łatwe, ale skoro przewaga krzywki jest znacząca, może być sensowna, aby kontynuować: musimy ponownie rozważyć pełna formuła: relerr EMAofdiscardeddata (1-k) n lastEMA więc n log (relerr lastEMA EMAofdiscardeddata) log (1-k) (log (relerr) log (lastEMA EMAofdiscardeddata)) log (1-k) centralnym punktem jest obliczenie lastEMA EMAofdiscardeddata (bez faktycznego obliczania lastEMA lub EMA) jest jeden przypadek, kiedy wiemy a-priori, że na przykład EMAofdiscardeddata lastEMA lt M (na przykład M 1000 lub M 1e6) w tym przypadku n lt (log (relerrM)) log (1 - k) jeśli nie możesz podać żadnego numeru M, musisz znaleźć dobry identyfikator ea do przeceniania EMAofdiscardeddata lastEMA Jedną szybką metodą może być M max (dane) min (dane) Parallelization Obliczenie może być ponownie napisane w formie, gdzie jest to proste dodanie niezależnych warunków: Tak więc jeśli język implementacyjny obsługuje równoległość zestaw danych można podzielić na 4 (lub 8 lub n. w zasadzie liczba dostępnych rdzeni procesora) kawałki i można obliczyć sumę warunków na każdym kawałku równolegle sumując poszczególne wyniki na końcu. Nie zajmuję się tym szczegółowo, ponieważ ta odpowiedź jest już strasznie długa i myślę, że koncepcja została już wyrażona. Dziękuję za to I39m za wykorzystanie tego na danych giełdowych, więc fakt, że starsze dane są na tym samym poziomie wielkości, co nowsze dane, zależy od wykorzystywanego czasu. Załóżmy, że w zakresie 200, będzie znacznie większa zmienność cen w dziennym przedziale czasowym (200 dni) niż w 5-minutowym okresie czasu (16 godzin). Będę eksperymentować z różnymi scenariuszami na rzeczywistych i symulowanych danych. Na nowych danych o zakresie lt 200 używam zbioru danych 1000 elementów. Ale robię też kilka testów wstecz w ciągu ostatnich kilku lat, więc nadal muszę załadować cały zestaw danych. Pomogłeś w obu sytuacjach, dziękuję ndash Lykegenes 16 lipca 14 o 15:11 Budowanie własnego rozszerzenia zdecydowanie poprawia wydajność. Oto dobry tutorial ze strony Zend. Niektóre dane dotyczące wydajności: Sprzęt: Ubuntu 14.04, PHP 5.5.9, 1-rdzeniowy procesor Intel 0.3.3 Ghz, 128 MB pamięci RAM (jego VPS). Przed (tylko PHP, 16 000 wartości). Rozszerzenie 500ms C, 16 000 wartości. Rozszerzenie 0.3ms C (100 000 wartości). 3,7 ms rozszerzenia (500 000 wartości). 28.0ms Ale Im pamięć ograniczona w tym momencie, używając 70 MB. Naprawię to i zaktualizuję odpowiednio liczby. traderema funkcja traderema () nie działa poprawnie. oblicza tylko średnią z ostatnich okresów. Postępuj zgodnie z następującym kodem dla traderema: function EMACalculator (limit, tablica) EMApreviousday array0 printr (array) multiplier1 (2limit1) EMAarray () EMA array0 Zamknij array1 while (limit) echoEMA is EMAn EMA (Close - EMApreviousday) multiplier1 EMApreviousday EMApreviousday Ograniczenie EMA - - return EMA gdzie limit akceptuje okres ema i array. akceptuj tablicę danych do obliczenia ema. Niestety, pokazany kod ma dwa główne błędy, ze względu na sposób, w jaki średnia jest przechowywana jako liczba całkowita. Aby to zobaczyć, wybierzmy alfa na 1024. Zaczynamy od wartości 0, a następnie dspemai32 zwróci 0 zgodnie z oczekiwaniami. Następnie zwiększ wartość do 1. tmp0 w dspemai32 będzie: tmp0 (int64t) 1 (1024) (int64t) 0 (65536 - 1024) 1024 0 64512 1024, więc zwróconą wartością jest: (int32t) ((tmp0 32768) 65536) ( 1024 32768) 65536 33792 65536 0 Tak więc dspemai32 będzie powracał 0, podczas gdy powinien (po wystarczająco długim czasie filtrowania) na końcu powrotu 1. Kod skutecznie implementuje filtr ze strefą martwą, nie zmieniając się, dopóki wejście nie różni się od średnio o 32768 lub więcej, lub różni się o - (32768 alfa) lub mniej. Wykonując powyższy przykład, zwiększ wartość do 31 (czyli mniej niż 32768alfa). tmp0 w dspemai32 będzie: tmp0 (int64t) 31 (1024) (int64t) 0 (65536 - 1024) 31744 0 64512 31744, więc zwróconą wartością jest: (int32t) ((tmp0 32768) 65536) (31744 32768) 65536 64512 65536 0 Tak więc dspemai32 będzie zwracał 0. Przy podnoszeniu wartości do 32, tmp0 w dspemai32 będzie: tmp0 (int64t) 32 (1024) (int64t) 0 (65536 - 1024) 32768 0 64512 32768, więc zwracana wartość wynosi: ( int32t) ((tmp0 32768) 65536) (32768 32768) 65536 65536 65536 1 Tak więc przynajmniej średnia przesuwa się w kierunku wartości wejściowej o 1. To jest dobre. Ale wtedy: tmp0 (int64t) 32 (1024) (int64t) 1 (65536 - 1024) 32768 1 64512 97280, więc zwrócona wartość wynosi: (int32t) ((tmp0 97280) 65536) (97280 32768) 65536 130048 65536 1 Tak dspemai32 powróci po 1, nigdy nie osiągając wartości wejściowej 32. Niedobrze. Drugi błąd to dzielenie całkowite (tmp0 32768) 65536. W C C podział całkowity będzie zaokrąglany w kierunku 0, więc w tej sytuacji martwa strefa jest jeszcze większa. Znacznie lepiej (i znacznie łatwiej) jest algorytm przedstawiony przez david. prentice na avrfreakscomment824765comment-824765: long total 0 int average 0 int N 0 working number of samples. suma ADCW dodać do sumy całkowitej, jeśli (N gt MAXSAMPLES) wystarczająca liczba próbek - średnia usunąć jedną inną N średnia całkowita liczba całkowita N
Comments
Post a Comment