====== Projekt konceptualny ====== ===== 1. Sformułowanie zadania projektowego ===== Projekt Giełdowych Analiz Dodawacz (GAD) będzie aplikacją umożliwiającą gromadzenie rekomendacji danych giełdowych oraz ich wymianę pomiędzy użytkownikami serwisu. Program będzie udostępniany klientom poprzez interfejs www. Produkt zainteresować może w szczególności osoby mające więcej wspólnego z analizą danych giełdowych, np. czynnych graczy. Dodatkowo, będzie on przydatnym narzędziem dla tych, którzy zaczynają swoją przygodę z tym tematem – pozwoli zapoznać się z mechanizmami rządzącymi giełdą oraz umożliwi sprawdzenie się w roli potencjalnego inwestora. Użytkownicy aplikacji korzystać będą z fikcyjnej waluty, której środki pozyskiwane będą w konsekwencji udanych (trafnych) przewidywań zachowań rynku giełdowego. W określonych warunkach, zgromadzone środki podlegać będą wymianie na prawdziwe pieniądze. Dla doświadczonych inwestorów stać więc może źródłem pozyskiwania realnych funduszy, natomiast dla pozostałych – serwisem pomocnym przy alokowaniu pieniędzy w akcje konkretnych spółek. ===== 2. Analiza stanu wyjściowego ===== Możemy wyróżnić szereg serwisów internetowych udostępniających rekomendacje giełdowe zarówno płatnie jak i darmowo. Serwisy darmowe działają zwykle z opóźnieniem – nawet kilkudniowym – co bardzo często ogranicza możliwości wykorzystania rekomendacji. Serwisy płatne, zwykle opierające się na stałym abonamencie, zwykle udostępniają wytworzone przez siebie rekomendacje wszystkim abonentom w tym samym momencie czasu – na stronie lub drogą e-mailową. Metod prognozowania jest bardzo wiele, niektóre opierają się na różnych wskaźnikach giełdowych i ich porównywaniu, inne na skomplikowanych algorytmach statystycznych, biorących pod uwagę dane krótko lub długookresowe, jednak nie spotkaliśmy się z serwisem działającym na bazie sieci neuronowej. Warto również wspomnieć o istniejących programach mających wspomagać granie na giełdzie. Tu również można wyróżnić darmowe i płatne wersje, jednak większość z nich oferuje jedynie swego rodzaju segregację danych i różnego typu wykresy statystyczne, które mogą stanowić podstawę do rekomendacji. Wszystkie rozwiązania skierowane są pod graczy giełdowych o różnym stopniu zaawansowania. Nasze rozwiązanie jest innowacyjne na skalę kraju. Główną zaletą będzie możliwość interaktywnego tworzenia i dobierania danych do sieci neuronowej, co nie zostało wprowadzone na rynek przez nikogo. Kolejnym atutem jest łączenie w sobie możliwości serwisu płatnego jak i darmowego, pozwalającego tworzyć i udostępniać rekomendacje, jak również sieci neuronowe wykorzystywane do analizy danych, a nawet uzyskanie na tym pewnego dochodu – użytkownik, którego rekomendacje są dobre i często wykorzystywane będzie w stanie na tym zarobić. ===== 3. Analiza wymagań użytkownika (wstępna) ===== W projekcie wyróżnia się dwa rozdaje użytkowników: Zalogowany Użytkownik (zwany dalej Użytkownikiem) oraz Gość. === Wymagania Użytkownika === - Konieczne (Must): * Przeglądania historycznych danych o kursach akcji * Dodanie własnych rekomendacji, nie wynikających z wyników sieci neuronowej, a z jego własnej wiedzy i doświadczenia * Wygenerowania sieci neuronowej, uczącej się na podstawie podzbioru historycznych danych giełdowych, według zdefiniowanych przez użytkownika parametrów * Zdefiniowania poziomu dostępności do rekomendacji swojej sieci. (minimalnie: dostępne dla wszystkich, dostępne dla zalogowanych, prywatne) * Przeglądanie wyników własnej sieci, wyników sieci ogólnodostępnych oraz globalnych statystyk (minimalnie: najczęściej rekomendowane, najlepsze rekomendacje ostatniego dnia, najlepsze rekomendacje ostatniego tygodnia) - Powinny się pojawić (Should): * Użytkownik będzie posiadał „konto” z wirtualnymi pieniędzmi za które będzie mógł kupować dostęp do niektórych części serwisu * Ustawienie poziomu dostępu do rekomendacji na „za opłatą” oraz ustalenie wysokości opłaty - Opcjonalne (Could): * Przeglądanie analizy technicznej * Możliwość wykorzystania wyników analizy technicznej jako wejście sieci neuronowej * Otrzymywanie powiadomień mailowych o nowych rekomendacjach własnej sieci * Możliwość „zapisania się” na otrzymywanie powiadomień mailowych o rekomendacjach konkretnych użytkowników === Wymagania Gościa === * Zarejestrowanie się oraz późniejsze zalogowanie przy użyciu loginu oraz hasła – Gość staje się Użytkownikiem * Przeglądania historycznych danych o kursach akcji * Przeglądanie wyników wyników sieci ogólnodostępnych oraz globalnych statystyk (minimalnie: najczęściej rekomendowane, najlepsze rekomendacje ostatniego dnia, najlepsze rekomendacje ostatniego tygodnia) ===== 4. Określenie scenariuszy użycia ===== === Rejestracja === - Użytkownik wprowadza pożądany login, posiadany adres e-mail oraz hasło (opcjonalnie imię i nazwisko, dane adresowe itp. - do przemyślenia + może system weryfikacji z obrazka) - Jeśli w bazie użytkowników nie ma użytkownika o takim samym loginie, bądź adresie e-mail tworzone jest nowe konto użytkownika, w przeciwnym wypadku użytkownik informowany jest o konflikcie - (Weryfikacja adresu e-mail?) === Logowanie === - Użytkownik wprowadza login i hasło - Jeśli dane odpowiadają danym w bazie to ładowana jest strona startowa użytkownika, zawierającą przeznaczone dla niego rekomendacje, w przeciwnym wypadku użytkownik jest informowany o błędzie === Odzyskiwanie hasła === - Użytkownik wprowadza adres e-mail powiązany z jego kontem - Jeśli w bazie danych jest przechowywana informacja o użytkowniku z takim adresem mailowym, na adres ten wysłany zostaje e-mail m.in. z loginem oraz linkiem, pod którym możliwe będzie wprowadzenie nowego hasła - Użytkownik dwukrotnie wprowadza nowe hasło; po wysłaniu zwalidowanego formularza hasło użytkownika zostaje zmienione na to nowo wprowadzone === Tworzenie sieci neuronowej === - Użytkownik ze swojej strony głównej wybiera odnośnik "Dodaj nową sieć" - Pojawia się formularz pozwalający na wybranie parametrów sieci, takich jak: * Typ sieci * Ilość warstw/neuronów * Algorytmu uczenia sieci - Następny formularz pozwala na ustawienie danych wejściowych, takich jak: * Wybór indeksu (WIG, WIG20, MIDWIG, itp.) * Wybór akcji * Wybór typu danych branych pod uwagę (kurs otwarcia/zamknięcia, wolumin, kurs średni) * Dane analizy technicznej - Formularz finalizacyjny pozwalający na: * Nadanie sieci nazwy * Ustawienie dostępności sieci (publiczna/prywatna) * Ustawienia dotyczące powiadomień === Dodawanie rekomendacji === - Użytkownik ze swojej strony głównej wybiera odnośnik "Dodaj nową rekomendację" - Użytkownik wypełnia odpowiednie pola formularza: * Nazwę rekomendacji * Spółkę * Przewidywany kurs * Dzień na który aktualna będzie rekomendacja * Opcjonalne: Pole z opisem na czym bazuje swoje wnioski === Przegląd danych historycznych === - Użytkownik ze swojej strony głównej wybiera odnośnik "Kursy" === Przegląd statystyk === - Użytkownik ze swojej strony głównej wybiera odnośnik "Statystyki" - Pojawia się strona z różnego rodzaju statystykami: * Najlepsze rekomendacje tygodnia/miesiąca/roku * Najlepiej rekomendujący użytkownicy tygodnia/miesiąca/roku * Najlepiej przewidujące sieci tygodnia/miesiąca/roku (Może być trudne w ocenie?) === Przegląd rekomendacji własnych oraz obserwowanych === - Lista będzie dostępna na stronie głównej użytkownika, wraz ze źródłami pochodzenia === Przegląd rekomendacji cudzych === - Użytkownik ze swojej strony głównej wybiera odnośnik "Dostępne rekomendacje" - Pojawia się lista dostępnych rekomendacji wraz z odnośnikami do dodawania do obserwowanych oraz rekomendującego. Dodatkowo dostępne są różne opcje filtrowania (kiedy dodana, czego dotyczy (indeksy/spółki)) ===== 5. Identyfikacja funkcji ===== === Rejestracja === Funkcja rejestrująca użytkownika w systemie; wymaga podania loginu, hasła oraz adresu e-mail, na który (w przypadku rejestracji zakończonej sukcesem) przesłany zostanie mail z linkiem aktywacyjnym. === Logowanie === Funkcja autoryzacyjna, pozwalająca na logowanie z wykorzystaniem loginu oraz hasła, przekazanych w procesie rejestracji; funkcja sprawdza poprawność wprowadzonej pary login-hasło z danymi znajdującymi się w bazie. Hasło sprawdzane jest w formie zaszyfrowanej. === Wylogowanie === Funkcja realizująca zakończenie aktualnie trwającej sesji użytkownika; w przypadku poprawnego wylogowania z systemu, użytkownik przekierowywany jest na stronę główną aplikacji. === Odzyskiwanie/zmiana hasła === W sytuacji, gdy użytkownik nie jest w stanie zalogować się do systemu, może skorzystać z opcji przypomnienia (a właściwie: odzyskiwania) hasła; polega to na przesłaniu na powiązany z kontem adres e-mail linka, pod którym możliwe jest wprowadzenie nowego hasła dla danego użytkownika. === Modyfikacja danych użytkownika === Funkcja pozwalająca na wprowadzanie zmian w profilu użytkownika zarejestrowanego; edycji podlegają hasło, adres e-mail i informacje dodatkowe; w przypadku zmiany hasła, wymagane jest wprowadzenie hasła aktualnego oraz dwukrotnie nowego; zmiana adresu mailowego wymaga jego aktywacji poprzez e-mail aktywacyjny. === Pobranie danych === Funkcja umożliwia pobranie z bazy wartości indeksów giełdowych jednej lub więcej spółek dla zadanego przedziału czasowego. === Pobranie rekomendacji === Funkcja umożliwia wyciągnięcie z bazy informacji o rekomendacjach użytkownika zalogowanego (o ile istnieje) oraz rekomendacji osób, których ustawienia prywatności na to pozwalają (rekomendacje publiczne/dla zalogowanych). === Dodanie rekomendacji zwykłej === Funkcja umożliwiająca wprowadzenie do bazy rekomendacji; wymaga podania wartości indeksu, identyfikatora spółki, której rekomendacja dotyczy oraz dnia, na który stan przewidujemy. === Dodanie rekomendacji opartej o sieć neuronową === Funkcja realizująca dodanie rekomendacji opartej o sieć neuronową, z przekazanym zestawem parametrów dla tej sieci; sieć taka będzie mieć za zadanie, na podstawie analiz danych historycznych określonych spółek dokonywać estymacji wskaźników giełdowych. === Edycja poziomu dostępności rekomendacji === Funkcja umożliwiająca zmianę dostępności rekomendacji dla innych użytkowników systemu. Dopuszczalne opcje: * rekomendacja publiczna (każdy może ją widzieć) * tylko zalogowanych * rekomendacja prywatna (dostępna tylko dla użytkownika, który ją utworzył) === Funkcja oceniająca === Funkcja obliczająca na ile zbieżne są wartości przewidziane do rzeczywistych, występujących w danym dniu. ===== 6. Analiza hierarchii funkcji projektowanej aplikacji (FHD – Functional Hierarchy Diagram) ===== === Funkcje obsługi kont użytkowników === * obsługa nowych użytkowników * rejestracja nowego użytkownika (minimalnie login, e-mail, hasło) * funkcja sprawdzająca, czy podany login/e-mail nie istnieje w bazie * właściwa rejestracja (dodanie konta do bazy) * powiadomienie mailowe o rejestracji * funkcja generująca link do aktywacji konta (potwierdzenia adresu e-mail) * funkcja wysyłająca odpowiedni e-mail * aktywacja konta * obsługa użytkowników zarejestrowanych * funkcja odpowiadająca za logowanie do serwisu * funkcja odpowiadająca za opcję przypominania hasła === Funkcje obsługi rekomendacji === * dodanie rekomendacji dla wybranej spółki, przewidywanego kursu oraz dnia, którego prognoza ma dotyczyć * dodanie rekomendacji w oparciu o sieć neuronową * ustawienie parametrów sieci * sprawdzenie, czy rekomendacja dla tej spółki w podanym dniu nie została wcześniej zdefiniowana przez tego samego użytkownika (przeciwdziałanie zwiększeniu szansy na trafną prognozę poprzez wprowadzanie wielu kursów) * weryfikacja trafności rekomendacji === Funkcje obsługi danych historycznych oraz statystyk === * wyświetlanie danych historycznych dla konkretnej spółki (spółek) z zadanego przedziału czasowego * (ocena rekomendacji, oceny trafności?) ===== 7. Diagram przepływu danych (DFD - Data Flow Diagram) ===== {{:pl:dydaktyka:ztb:2011:projekty:gielda:gaddfd.png|}} ===== 8. Wybór encji (obiektów) i ich atrybutów ===== === Użytkownik === * id * login * hasło (zakodowane) * e-mail * data rejestracji * data ostatniego logowania * flaga aktywności * rola === Spółka === * id spółki * nazwa * indeks (WIG, WIG20, midWIG itp.) === Rekomendacja === * id rekomendacji * nazwa rekomendacji * id spółki * id (właściciel rekomendacji) * dzień na który przewidujemy * przewidywana wartość * dostępność rekomendacji * opis/komentarz do rekomendacji * id sieci neuronowej (jeśli dotyczy) === Sieć neuronowa === * id sieci neuronowej * nazwa sieci * id (właściciela sieci) * typ sieci * zestaw parametrów opisujących sieć (warstwy/liczby neuronów/wagi neuronów) * (czy dane z których uczymy nie będą dotyczyły tylko sieci z rekomendacjami? To pozwoli na wielokrotne wykorzystanie?) ===== 9. Powiązania pomiędzy encjami (ERD - Entity-Relationship Diagram) ===== {{:pl:dydaktyka:ztb:2011:projekty:gielda:gad_erd.png|}} ===== 10. Diagramy przejść między stanami (STD - State Transition Diagram) ===== {{:pl:dydaktyka:ztb:2011:projekty:gielda:gadstd1.png?800}} ====== Projekt logiczny ====== ===== 1. Projektowanie tabel, kluczy, kluczy obcych, powiązań między tabelami, indeksów, etc. w oparciu o zdefiniowany diagram ERD ===== === Zaprojektowane klucze obce i powiązania między tabelami === ^ Nazwa klucza ^ Tabela nadrzędna ^ Tabela zależna ^ Kolumna nadrzędna ^ Kolumna zależna ^ Typ relacji ^ ON DELETE ^ ON UPDATE ^ | fk_neural_networks_neurons_f_neurons | neurons | neural_networks_neurons | neuron_id | neuron_id_from | 1 : 1, m | NO ACTION | CASCADE | | fk_neural_networks_neurons_t_neurons | neurons | neural_networks_neurons | neuron_id | neuron_id_to | 1 : 1, m | NO ACTION | CASCADE | | fk_neurons_neural_networks | neural_networks | neurons | network_id | network_id | 1 : 1, m | NO ACTION | CASCADE | | fk_recommendations_access_levels | access_levels | recommendations | access_level_id | access_level_id | 1 : 1, m | NO ACTION | CASCADE | | fk_recommendations_companies | companies | recommendations | company_code | company_code | 1 : 1, m | NO ACTION | CASCADE | | fk_recommendations_neural_networks | neural_networks | recommendations | network_id | network_id | 1 : 0, 1, m | NO ACTION | CASCADE | | fk_recommendations_users | users | recommendations | user_id | owner_id | 1 : 1, m | NO ACTION | CASCADE | | fk_stock_values_companies | companies | stock_values | company_code | company_code | 1 : 1, m | NO ACTION | CASCADE | | fk_users_roles | roles | users | role_id | role_id | 1 : 1, m | NO ACTION | CASCADE | === Nałożone indeksy === * recommendations_company_code_Idx - dot. kolumny company_code w tabeli recommendations * recommendations_owner_id_Idx - dot. kolumny owner_id w tabeli recommendations * recommendations_prediction_day_Idx - dot. kolumny prediction_day w tabeli recommendations === Kompletny kod w języku MySQL tworzący strukturę bazodanową === SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; CREATE TABLE IF NOT EXISTS `access_levels` ( `access_level_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `description_short` varchar(45) COLLATE utf8_polish_ci NOT NULL, `description_long` varchar(200) COLLATE utf8_polish_ci NOT NULL, PRIMARY KEY (`access_level_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `companies` ( `company_code` varchar(10) COLLATE utf8_polish_ci NOT NULL, `company_name` varchar(45) COLLATE utf8_polish_ci NOT NULL, PRIMARY KEY (`company_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci; CREATE TABLE IF NOT EXISTS `neural_networks` ( `network_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(45) COLLATE utf8_polish_ci NOT NULL, `inputs_no` int(10) unsigned NOT NULL DEFAULT '0', `outputs_no` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `neural_networks_neurons` ( `neuron_id_from` int(10) unsigned NOT NULL, `neuron_id_to` int(10) unsigned NOT NULL, `weight` double unsigned NOT NULL, PRIMARY KEY (`neuron_id_from`,`neuron_id_to`), KEY `fk_neural_networks_neurons_t_neurons` (`neuron_id_to`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci; CREATE TABLE IF NOT EXISTS `neurons` ( `neuron_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `network_id` int(10) unsigned NOT NULL, `bias` double NOT NULL, PRIMARY KEY (`neuron_id`), KEY `fk_neurons_neural_networks` (`network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `recommendations` ( `recommendation_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `owner_id` int(10) unsigned NOT NULL, `company_code` varchar(10) COLLATE utf8_polish_ci NOT NULL, `predicted_value` decimal(10,2) unsigned NOT NULL, `prediction_day` date NOT NULL, `network_id` int(10) unsigned DEFAULT NULL, `access_level_id` int(10) unsigned NOT NULL, PRIMARY KEY (`recommendation_id`), KEY `recommendations_company_code_Idx` (`company_code`), KEY `recommendations_owner_id_Idx` (`owner_id`), KEY `recommendations_prediction_day_Idx` (`prediction_day`), KEY `fk_recommendations_access_levels` (`access_level_id`), KEY `fk_recommendations_neural_networks` (`network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `stock_values` ( `company_code` varchar(10) COLLATE utf8_polish_ci NOT NULL, `date` date NOT NULL, `value` decimal(10,2) NOT NULL, PRIMARY KEY (`company_code`,`date`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci; CREATE TABLE IF NOT EXISTS `users` ( `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `login` varchar(45) COLLATE utf8_polish_ci NOT NULL, `email` varchar(45) COLLATE utf8_polish_ci NOT NULL, `password` varchar(32) COLLATE utf8_polish_ci NOT NULL, `registration_time` datetime NOT NULL, `last_login_time` datetime NOT NULL, `is_active` tinyint(3) unsigned NOT NULL DEFAULT '0', `role_id` int(10) unsigned NOT NULL DEFAULT '1', PRIMARY KEY (`user_id`), KEY `fk_users_user_roles` (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `user_roles` ( `role_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `description` varchar(45) COLLATE utf8_polish_ci NOT NULL, PRIMARY KEY (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; INSERT INTO `user_roles` (`role_id`, `description`) VALUES (1, 'Użytkownik'); ALTER TABLE `neural_networks_neurons` ADD CONSTRAINT `fk_neural_networks_neurons_t_neurons` FOREIGN KEY (`neuron_id_to`) REFERENCES `neurons` (`neuron_id`) ON DELETE NO ACTION ON UPDATE CASCADE, ADD CONSTRAINT `fk_neural_networks_neurons_f_neurons` FOREIGN KEY (`neuron_id_from`) REFERENCES `neurons` (`neuron_id`) ON DELETE NO ACTION ON UPDATE CASCADE; ALTER TABLE `neurons` ADD CONSTRAINT `fk_neurons_neural_networks` FOREIGN KEY (`network_id`) REFERENCES `neural_networks` (`network_id`) ON DELETE NO ACTION ON UPDATE CASCADE; ALTER TABLE `recommendations` ADD CONSTRAINT `fk_recommendations_users` FOREIGN KEY (`owner_id`) REFERENCES `users` (`user_id`) ON DELETE NO ACTION ON UPDATE CASCADE, ADD CONSTRAINT `fk_recommendations_access_levels` FOREIGN KEY (`access_level_id`) REFERENCES `access_levels` (`access_level_id`) ON DELETE NO ACTION ON UPDATE CASCADE, ADD CONSTRAINT `fk_recommendations_companies` FOREIGN KEY (`company_code`) REFERENCES `companies` (`company_code`) ON DELETE NO ACTION ON UPDATE CASCADE, ADD CONSTRAINT `fk_recommendations_neural_networks` FOREIGN KEY (`network_id`) REFERENCES `neural_networks` (`network_id`) ON DELETE NO ACTION ON UPDATE CASCADE; ALTER TABLE `stock_values` ADD CONSTRAINT `fk_stock_values_companies` FOREIGN KEY (`company_code`) REFERENCES `companies` (`company_code`) ON DELETE NO ACTION ON UPDATE CASCADE; ALTER TABLE `users` ADD CONSTRAINT `fk_users_user_roles` FOREIGN KEY (`role_id`) REFERENCES `user_roles` (`role_id`) ON DELETE NO ACTION ON UPDATE CASCADE; ===== 2. Słowniki danych ===== - roles: tabela słownikowa przechowująca identyfikatory poszczególnych ról użytkowników systemu (administrator, zwykły użytkownik itp.) * role_id (id roli; klucz główny, wartość unikalna) - INT UNSIGNED NOT NULL AUTO_INCREMENT, * description (określenie roli) - VARCHAR(45) NOT NULL. - users: tabela przechowująca informacje o użytkownikach systemu * user_id (id użytkownika; klucz główny, wartość unikalna) - INT UNSIGNED NOT NULL AUTO_INCREMENT, * login (nazwa użytkownika) - VARCHAR(45) NOT NULL, * email (adres e-mail) - VARCHAR(45) NOT NULL, * password (hasło użytkownika, zaszyfrowane algorytmem md5) - VARCHAR(32) NOT NULL, * registration_time (data rejestracji w systemie) - DATETIME NOT NULL, * last_login_time (data ostatniego zalogowania) - DATETIME NOT NULL, * is_active (flaga określająca, czy użytkownik jest aktywny) - TINYINT(1) NOT NULL DEFAULT 0, * role_id (id roli z tabeli roles) - INT NOT NULL DEFAULT 1. - recommendations: tabela, w której przechowywane są rekomendacje (przewidywane wartości na konkretne terminy) spółek, wprowadzane przez użytkowników systemu * recommendation_id (unikalny identyfikator rekomendacji, klucz główny) - INT UNSIGNED NOT NULL AUTO_INCREMENT, * owner_id (identyfikator autora/właściciela z tabeli users) - INT UNSIGNED NOT NULL, * company_code (identyfikator firmy z tabeli companies) - VARCHAR(10) NOT NULL, * predicted_value (przewidywana wartość akcji na konkretną datę) - DECIMAL NOT NULL, * predicted_day (dzień, którego dotyczy szacowanie wartości) - DATE NOT NULL, * access_level (poziom dostępu, z tabeli access_levels) - INT NOT NULL, * network_id (opcjonalny identyfikator sieci neuronowej, która wyznaczyła rekomendację) - INT UNSIGNED NULL DEFAULT NULL. - companies: tabela z identyfikatorami firm * company_code (unikalny kod spółki, klucz główny) - VARCHAR(10) NOT NULL, * company_name (pełna nazwa spółki) - VARCHAR(45) NOT NULL, * index_id - stock_values: tabela z faktycznymi wartościami spółek w konkretnych dniach * company_code (kod spółki, z tabeli companies) - VARCHAR(10) NOT NULL, * date (data zanotowania wartości wskaźnika) - DATE NOT NULL, * value (wartość spółki w określonym dniu) - DECIMAL NOT NULL. - access_levels: tabela słownikowa dla opisów poszczególnych ustawień prywatności * access_level_id (unikalny identyfiaktor poziomu dostępu, klucz główny) - INT UNSIGNED NOT NULL AUTO_INCREMENT, * description_short (krótki opis poziomu dostępu) - VARCHAR(45) NOT NULL, * description_long (pełny opis poziomu dostępu) - VARCHAR(200) NOT NULL. - neural_networks: tabela określająca podstawowe parametry sieci neuronowych (nazwę, liczbę wejść i wyjść) * network_id (unikalny identyfikator sieci neuronowej, klucz główny) - INT UNSIGNED NOT NULL AUTO_INCREMENT, * name (nazwa sieci neuronowej) - VARCHAR(45) NOT NULL, * inputs (liczba wejść) - INT NOT NULL DEFAULT 0, * outputs (liczba wyjść) - INT NOT NULL DEFAULT 0. - neurons: tabela precyzująca parametr 'bias' każdego neuronu * neuron_id (unikalny identyfikator neuronu, klucz główny) - INT UNSIGNED NOT NULL AUTO_INCREMENT, * network_id (identyfikator sieci neuronowej z tabeli neural_networks) - INT NOT NULL, * bias (parametr 'bias' konkretnego neuronu) - DOUBLE NOT NULL. - neural_networks_neurons: tabela definiująca połączenia między poszczególnymi neuronami w ramach sieci neuronowej * neuron_id_from (identyfikator neuronu, od którego wychodzi połączenie, element złożonego klucza głównego) - INT UNSIGNED NOT NULL, * neuron_id_to (identufikator neuronu, do którego wchodzi połączenie, element złożonego klucza głównego) - INT UNSIGNED NOT NULL, * weight (waga połączenia między neuronami) - DOUBLE NOT NULL. ===== 3. Analiza zależności funkcyjnych i normalizacja tabel (dekompozycja do 3NF, BCNF, 4NF, 5NF) ===== === Analiza zależności funkcyjnych === == Pierwsza postać normalna (1NF) == **Wymagania:** * wartości atrybutów we wszystkich tabelach są atomiczne (niepodzielne), * każda tabela posiada klucz główny, * znaczenie danych nie zależy od kolejności rekordów. **Przedstawiana baza jest 1NF.** == Druga postać normalna (2NF) == **Wymagania:** * zachodzą warunki na 1NF, * każda kolumna jest funkcyjnie zależna od __całego__ klucza głównego. **Przedstawiana baza jest 2NF.** == Trzecia postać normalna (3NF) == **Wymagania:** * zachodzą warunki na 2NF, * wszystkie pola, które nie wchodzą w skład klucza głównego są od niego zależne __bezpośrednio__. **Przedstawiana baza jest 3NF.** ===== 4. Projektowanie operacji na danych - przykładowe zapytania ===== Rejestracja użytkownika INSERT INTO users (login, email, password, registration_time) VALUES ('justin', 'justin@domain.com', '61c81371ae4404d7100202d90bee987e', NOW()) Sprawdzenie, czy nie istnieją użytkownicy o podanym e-mailu/loginie (jeśli zwrócona wartość != 0, istnieją) SELECT COUNT(1) FROM users WHERE login='justin' OR email='justinmail@domain.com' Modyfikacja danych użytkownika UPDATE users SET (login, email) VALUES ('harry', 'harry@domain.com') Dodanie nowej spółki INSERT INTO companies (company_code, company_name) VALUES ('NS', 'Nowa spółka') Pobranie danych historycznych wybranych spółek SELECT company_code, date, value FROM stock_values WHERE company_code IN ('XXX', 'YYY', 'ZZZ') AND date BETWEEN 2011-03-04 AND 2011-05-21 Dodanie dziennego ratingu dla spółki INSERT INTO stock_values (company_code, date, value) VALUES ('NS', DATE(NOW()), 123) Pobranie rekomendacji użytkownika zalogowanego oraz tych, które są dla niego widoczne SELECT * FROM recommendations INNER JOIN access_levels ON access_levels.access_level_id=recommendations.access_level_id WHERE owner_id={{id_uzytkownika_zalogowanego}} OR access_levels.description_short IN ('publiczny', 'dla_zalogowanych') Dodanie rekomendacji dla wybranej spółki, przewidywanego kursu oraz dnia, którego prognoza ma dotyczyć - wraz z ustaleniem poziomu dostępu INSERT INTO recommendations (owner_id, company_code, predicted_value, prediction_day, access_level_id) VALUES ({{id_uzytkownika_zalogowanego}}, 'NS', 444, '2011-10-10', ( SELECT access_level_id FROM access_levels WHERE description_short='publiczny') ) Dodanie rekomendacji dla wybranej spółki, z wykorzystaniem parametryzowanej sieci neuronowej ====== Raport końcowy ====== ===== 1. Implementacja bazy danych ===== {{:pl:dydaktyka:ztb:2011:projekty:gielda:gad_erd.png|}} W oparciu o powyższy diagram ERD, utworzono pustą bazę danych na silniku MySQL o strukturze zaprezentowanej na poniższym listingu: SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; CREATE TABLE IF NOT EXISTS `access_levels` ( `access_level_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `description_short` varchar(45) COLLATE utf8_polish_ci NOT NULL, `description_long` varchar(200) COLLATE utf8_polish_ci NOT NULL, PRIMARY KEY (`access_level_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `companies` ( `company_code` varchar(10) COLLATE utf8_polish_ci NOT NULL, `company_name` varchar(45) COLLATE utf8_polish_ci NOT NULL, PRIMARY KEY (`company_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci; CREATE TABLE IF NOT EXISTS `neural_networks` ( `network_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(45) COLLATE utf8_polish_ci NOT NULL, `inputs_no` int(10) unsigned NOT NULL DEFAULT '0', `outputs_no` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `neural_networks_neurons` ( `neuron_id_from` int(10) unsigned NOT NULL, `neuron_id_to` int(10) unsigned NOT NULL, `weight` double unsigned NOT NULL, PRIMARY KEY (`neuron_id_from`,`neuron_id_to`), KEY `fk_neural_networks_neurons_t_neurons` (`neuron_id_to`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci; CREATE TABLE IF NOT EXISTS `neurons` ( `neuron_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `network_id` int(10) unsigned NOT NULL, `bias` double NOT NULL, PRIMARY KEY (`neuron_id`), KEY `fk_neurons_neural_networks` (`network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `recommendations` ( `recommendation_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `owner_id` int(10) unsigned NOT NULL, `company_code` varchar(10) COLLATE utf8_polish_ci NOT NULL, `predicted_value` decimal(10,2) unsigned NOT NULL, `prediction_day` date NOT NULL, `network_id` int(10) unsigned DEFAULT NULL, `access_level_id` int(10) unsigned NOT NULL, PRIMARY KEY (`recommendation_id`), KEY `recommendations_company_code_Idx` (`company_code`), KEY `recommendations_owner_id_Idx` (`owner_id`), KEY `recommendations_prediction_day_Idx` (`prediction_day`), KEY `fk_recommendations_access_levels` (`access_level_id`), KEY `fk_recommendations_neural_networks` (`network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `stock_values` ( `company_code` varchar(10) COLLATE utf8_polish_ci NOT NULL, `date` date NOT NULL, `value` decimal(10,2) NOT NULL, PRIMARY KEY (`company_code`,`date`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci; CREATE TABLE IF NOT EXISTS `users` ( `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `login` varchar(45) COLLATE utf8_polish_ci NOT NULL, `email` varchar(45) COLLATE utf8_polish_ci NOT NULL, `password` varchar(32) COLLATE utf8_polish_ci NOT NULL, `registration_time` datetime NOT NULL, `last_login_time` datetime NOT NULL, `is_active` tinyint(3) unsigned NOT NULL DEFAULT '0', `role_id` int(10) unsigned NOT NULL DEFAULT '1', PRIMARY KEY (`user_id`), KEY `fk_users_user_roles` (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `user_roles` ( `role_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `description` varchar(45) COLLATE utf8_polish_ci NOT NULL, PRIMARY KEY (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci AUTO_INCREMENT=1 ; INSERT INTO `user_roles` (`role_id`, `description`) VALUES (1, 'Użytkownik'); ALTER TABLE `neural_networks_neurons` ADD CONSTRAINT `fk_neural_networks_neurons_t_neurons` FOREIGN KEY (`neuron_id_to`) REFERENCES `neurons` (`neuron_id`) ON DELETE NO ACTION ON UPDATE CASCADE, ADD CONSTRAINT `fk_neural_networks_neurons_f_neurons` FOREIGN KEY (`neuron_id_from`) REFERENCES `neurons` (`neuron_id`) ON DELETE NO ACTION ON UPDATE CASCADE; ALTER TABLE `neurons` ADD CONSTRAINT `fk_neurons_neural_networks` FOREIGN KEY (`network_id`) REFERENCES `neural_networks` (`network_id`) ON DELETE NO ACTION ON UPDATE CASCADE; ALTER TABLE `recommendations` ADD CONSTRAINT `fk_recommendations_users` FOREIGN KEY (`owner_id`) REFERENCES `users` (`user_id`) ON DELETE NO ACTION ON UPDATE CASCADE, ADD CONSTRAINT `fk_recommendations_access_levels` FOREIGN KEY (`access_level_id`) REFERENCES `access_levels` (`access_level_id`) ON DELETE NO ACTION ON UPDATE CASCADE, ADD CONSTRAINT `fk_recommendations_companies` FOREIGN KEY (`company_code`) REFERENCES `companies` (`company_code`) ON DELETE NO ACTION ON UPDATE CASCADE, ADD CONSTRAINT `fk_recommendations_neural_networks` FOREIGN KEY (`network_id`) REFERENCES `neural_networks` (`network_id`) ON DELETE NO ACTION ON UPDATE CASCADE; ALTER TABLE `stock_values` ADD CONSTRAINT `fk_stock_values_companies` FOREIGN KEY (`company_code`) REFERENCES `companies` (`company_code`) ON DELETE NO ACTION ON UPDATE CASCADE; ALTER TABLE `users` ADD CONSTRAINT `fk_users_user_roles` FOREIGN KEY (`role_id`) REFERENCES `user_roles` (`role_id`) ON DELETE NO ACTION ON UPDATE CASCADE; ===== 2. Zdefiniowanie interfejsów do prezentacji, edycji i obsługi danych ===== {{:pl:dydaktyka:ztb:2011:projekty:gielda:scr1.jpg|}} Strona startowa {{:pl:dydaktyka:ztb:2011:projekty:gielda:scr2.jpg|}} Ekran logowania {{:pl:dydaktyka:ztb:2011:projekty:gielda:scr3.jpg|}} Ekran rejestracji nowego użytkownika {{:pl:dydaktyka:ztb:2011:projekty:gielda:scr4.jpg|}} Ekran dodawania sieci neuronowej {{:pl:dydaktyka:ztb:2011:projekty:gielda:scr5.jpg|}} Ekran wyświetlający rekomendacje {{:pl:dydaktyka:ztb:2011:projekty:gielda:scr6.jpg|}} Ekran dodawania nowej rekomendacji ===== 3. Zdefiniowanie dokumentów do przetwarzania i prezentacji danych ===== Aplikacja nie używa dokumentów do prezentacji danych. Jedynym dokumentem wykorzystywanym jest plik .csv, pobierany za pośrednictwem API, zawierający dane giełdowe. ===== 4. Zdefiniowanie panelu sterowania aplikacji ===== Na tym etapie rozwoju aplikacja nie wymagała stworzenia panelu sterowania. ===== 5. Zdefiniowanie makropoleceń dla realizacji typowych operacji ===== Typowe operacje na bazie danych wykonywane są przy pomocy frameworka do realizacji warstwy dostępu do danych [[http://www.hibernate.org/|Hibernate]]. Pełni on funkcję mapera obiektowo-relacyjnego (ORM) i wykonuje podstawowe zapytania do bazy danych. Z wielu dostępnych narzędzi tego typu, powyższe zostało wybrane z racji dojrzałości projektu, jak i dostarczonej do niego dokumentacji. ===== 6. Uruchamianie i testowanie aplikacji ===== Aplikacja uruchamiana oraz testowana była na lokalnych środowiskach jej twórców. Poszczególne komponenty i funkcjonalności były regularnie testowane w miarę rozwoju projektu, w celu możliwie szybkiego wyeliminowania ewentualnych niepoprawnych zachowań i innych sytuacji nieporządanych. ===== 7. Wprowadzanie danych ===== System opiera swe działanie o dane dostarczane przez serwis [[http://finance.yahoo.com|Charts - Yahoo! Finance]] za pośrednictwem API http://finance.yahoo.com/charts. Fragment kodu (w języku Java), budujący adres uri dla danych do pobrania: StringBuilder uri = new StringBuilder(); uri.append("http://ichart.finance.yahoo.com/table.csv"); uri.append("?s=").append(company.getSymbol()); uri.append("&a=").append(start.getMonth()); uri.append("&b=").append(start.getDay()); uri.append("&c=").append(start.getYear() + 1900); uri.append("&d=").append(end.getMonth()); uri.append("&e=").append(end.getDay()); uri.append("&f=").append(end.getYear() + 1900); uri.append("&g=d"); Aplikacja "odpytuje" API poprzez (zbudowane z powyższego) żądanie HTTP GET do Yahoo!, a serwis zwraca oczekiwane wartości (lub komunikat o błędzie, w przypadku przekazania niepoprawnych parametrów). Tym sposobem otrzymujemy wartości dzienne danego, sprecyzowanego wskaźnika z określonego przedziału czasowego. Na potrzeby implementacji oraz weryfikacji działania, aplikacja pozwala na import informacji o cenach złota, ropy oraz wartości indeksu Dow Jones. Na chwilę obecną import przeprowadzany jest ręcznie, docelowo wykonywane będzie to automatycznie. ===== 8. Wdrażanie systemu do użytkowania ===== W celu uruchomienia aplikacji na nowej maszynie produkcyjnej, należy wykonać następujące czynności: * zaimportować strukturę bazodanową do docelowego serwera MySQL, * zaktualizować sekcję dotyczącą parametrów bazy w pliku konfiguracyjnym projektu, * uruchomić kontener servletów TomCat, * wdrożyć projekt na serwer produkcyjny, ===== 9. Przeprowadzenie szkolenia użytkowników ===== Aplikacja nie jest bardzo skomplikowana, a interfejs w miarę intuicyjny. Korzystanie z niej nie powinno sprawić problemów użytkownikom systemu. ===== 10. Zapewnienie dokumentacji technicznej i użytkowej ===== Jedyną rzeczą jaką dobrzy byłoby dostarczyć użytkownikom aplikacji są podstawowe informacje o sieciach neuronowych oraz sposobie ich konstruowania i wykorzystania do przewidzenia danych giełdowych. ===== 11. Zapewnienie obsługiwania systemu po wdrożeniu ===== Obsługa aplikacji po wdrożeniu to zarówno kontrola poprawności działania aplikacji i bazy danych jak również moderacja zawartości. Autorzy powinni umożliwić i reagować na feedback od użytkowników. Ważne jest także skalowalność czyli przygotowanie bazy, serwera jak i aplikacji do znacznego wzrostu obciążenia w przypadku zwiększenia liczby użytkowników. ===== 12. Rozwijanie i modyfikowanie aplikacji ===== Podstawowym kierunkiem dalszego rozwoju aplikacji powinno być dodanie obsługi większej ilości spółek. Kolejnym dobrym pomysłem będzie dodanie większej ilości parametrów do modułu tworzenia sieci neuronowych w celu umożliwienia dokładniejszych obliczeń. Dodanie szaty graficznej znacznie wpłynęło by na komfort i wrażenia wizualne użytkowników. ===== 13. Opracowanie doświadczeń wynikających z realizacji projektu ===== Realizacja omawianego projektu wiązała się z koniecznością poznania nieużywanych przez nas do tej pory technologii i rozwiązań. Przede wszystkim dotyczy to frameworków Google Web Toolkit (GWT) oraz Hibernate. O ile same w sobie są raczej przyjazne dla developerów, wykorzystanie ich razem - w jednym projekcie - nastręczyło nam dość sporych trudności i było znaczącą przyczyną opóźnienia dalszych prac. Niestety na chwilę obecną brakuje wyczerpujących dokumentacji dotyczących podpinania Hibernate'a do aplikacji tworzonej w GWT, dlatego też nie obyło się bez "eksperymentowania", którego normalnie bylibyśmy w stanie uniknąć. Google Web Toolkit dla twórców aplikacji internetowych jest niewątpliwie ciekawym rozwiązaniem. Pozwala on na tworzenie serwisów AJAXowych z wykorzystaniem języka Java. Jest to możliwe poprzez mechanizmy przeprowadzające kompilację kodu Javowego stanowiącego część kliencką aplikacji do JavaScriptu, HTMLa i CSSa. Hibernate natomiast, niezwykle upraszcza i przyspiesza wykonywanie operacji na strukturach bazodanowych. Pełni on funkcję mapera obiektowo-relacyjnego, co w konsekwencji pozwala na budowanie zapytań do bazy w oparciu o struktury obiektowe. Przy korzystaniu z tego typu rozwiązań, pod rozwagę należy wziąć kwestie wydajnościowe. Mapowanie obiektowo-relacyjne niewątpliwie jest wygodne (i atrakcyjne), w szczególności z punktu widzenia programisty nieobytego w językach SQLowych. Bez praktycznej znajomości SQLa można swobodnie wykonywać większość operacji bazodanowych. Jednak należy pamiętać, że "odpytywanie" bazy w taki sposób wymaga więcej zasobów, z racji samej natury translacji O-R. Dlatego też, w sytuacjach, gdzie wydajność staje się czynnikiem krytycznym, nieraz bardziej odpowiednie okaże się korzystanie ze "standardowych" zapytań. ===== 14. Wykaz literatury, linki i załączniki ===== [[http://finance.yahoo.com/charts|Charts - Yahoo! Finance]] [[http://www.hibernate.org/|Hibernate: Relational Persistence for Java and .NET]] [[http://en.wikipedia.org/wiki/Object-relational_mapping|Object-relational mapping]] [[http://code.google.com/intl/pl-PL/webtoolkit/|Google Web Toolkit]]