jam231 / sia

Stock market server (part of stock market simulation system).
1 stars 0 forks source link

Niezbędnę powiadomienia dla klienta #13

Closed kaiks closed 11 years ago

kaiks commented 11 years ago

Klient przy logowaniu chce mieć na pewno (fajnie by było mieć to dziś) następujące informacje dla danej akcji:

Pytanie jest jeszcze o realizacje dla tych funkcjonalności. Ja bym powiedział, że potrzebne są funkcje po dwóch stronach, tj. zarówno bazy jak i aplikacji.

W bazie musimy mieć pobieranie (i przekazywanie aplikacji) takiego rekordu danych na wypadek gdybyśmy coś już w bazie mieli a serwer się dopiero uruchamiał. Inaczej mówiąc, niezbędne do inicjalizacji struktury danych która by to przechowywała w QT.

W QT natomiast trzymać np. hash trzech par (lub trzy hashe): zlecenia[id_akcji] = { (zrealizowane, ile), (najdrozsze kupno, ile), (najtansza sprzedaz, ile) } gdzie pierwszy parametr jest wartością cenową, drugi ilością akcji.

Implementacja tej struktury nie jest najwyższego priorytetu chyba, skoro tak czy inaczej zaimplementuje to w bazie danych.

Po stronie bazy danych funkcjonalność będzie wyglądać następująco: zlecenia_info(id_zasobu) -> (zrealizowane_cena, ilosc, data, kupno_cena, ilosc, sprzedaz_cena, ilosc).

Natomiast by wybrać dla każdej z akcji: SELECT zlecenia_info(id_zasobu) FROM zasob WHERE id>1;

To jest jakiś koncept na razie. Wszelkie sugestie są mile widziane

kaiks commented 11 years ago

Zamiast zlecenia_info dodałem funkcje: najlepsze_kupno najlepsza_sprzedaz i ostatnia_transakcja ktore przyjmuja id_zasobu (a zwracają cenę i ilość (i datę dla ostatnia_transakcja)

@jam231 jak rozumiem NEW_TRANSACTION powiadamia o nowym zleceniu

w związku z tym wnoszę o zmianę nazwy na NEW_ORDER

jam231 commented 11 years ago

Przychylam się do prośby o zmiane nazwy na NEW_ORDER.

jam231 commented 11 years ago

Subskrybent danego zasobu (instrumentu finansowego) na obecna chwile dostaje informacje o najlepszej ofercie sprzedaży albo kupna, albo sprzedaży i kupna, zależnie od tego którego kanału komunikacyjnego użyje baza (przy ch_zmiana wysyłane są obie dane). Jeżeli takich ofert nie ma żadna wiadomość nie jest wysyłana (może powinna być jakaś o tym, ze nikt nie chce już sprzedawać\kupować instrumentu X ?). Najlepsze oferty są przetrzymywane w dwóch cache'ach - na razie nie jest to wykorzystywane, ale rozumiem, że będziemy chcieli robić różne wariacje dot. tego, np. nowozasubskrybowanego przeslij dwie informacje o najlepszej ofercie kupna\sprzedazy (tutaj znowu pojawia sie problem jak dać znać gdy jednej z nich nie bedzie)

Giełda pamięta również ostatnią transakcje. Wysyła ją nowozalogowanym. Pojawił się problem jak nalezy się zachować kiedy było jeszcze żadnej transakcji, w takim wypadku po prostu giełda nie wysyla zadnej informacji logujacemu sie uzytkownikowi. Gdy nowe transakcje sa wprowadzane, dokonuje sie aktualizacja.

kaiks commented 11 years ago

Potrzebne są informacje dotyczące akcji i zasobów użytkownika. Żeby już się nie grzebać z zapytaniami po stronie QT, zrobiłem odpowiednie funkcje SQLowe.

Można to obsługiwać requestami (GetStocks, i dodać podobne: GetOrders).

Funkcje SQL: dobra_uz(id_uz), zlecenia_uz(id_uz)

kaiks commented 11 years ago

zrób ktoś obsługę GetStocks i GetOrder :(

jam231 commented 11 years ago

Lamentuj... Ja będę mógł się za to wziąć za jakieś.. 2-3h

kaiks commented 11 years ago

pozostaje getorders, które jeśli nikt inny mnie nie uprzedzi, zrobię dziś

nie wiem, czy sposób w jaki piszę jest Mądry i Bezpieczny, więc zapraszam do poprawiania mojego kodu

kaiks commented 11 years ago

Marek na swojej gałęzi dodał funkcjonalności GetMyStocks oraz GetMyOrders, które jakośtam działają

kaiks commented 11 years ago

jako kolejny krok proponuję pakiet: GET_STOCK_INFO stock_id

i odpowiedź: STOCK_INFO STOCK_ID [NAJLEPSZE ZLECENIE_KUPNA] [NAJLEPSZE_ZLECENIE_SPRZEDAZY] [OSTATNIA_TRANSAKCJA]

gdzie kazde z [pól] ma dwie wartosci: cena, ilosc i byc moze ostatnia_transakcja ma jeszcze date

jesli nikt z was go nie zaimplementuje dzis do wieczora to sam to zrobie

marimarek commented 11 years ago

A jest coś do tego po stronie bazy? Jak tak to w serwerze ja to mogę zrobić.

kaiks commented 11 years ago

Jest po stronie serwera m_cachedBestSellOrders m_cachedBestBuyOrders

a po stronie bazy jest do OSTATNIA_TRANSAKCJA

CREATE OR REPLACE FUNCTION ostatnia_transakcja(in zasob integer, out integer, out integer, out timestamp with time zone)
    AS $$ SELECT cena,ilosc,czas FROM (SELECT cena,ilosc,czas,id_zasobu FROM zrealizowane_zlecenie UNION SELECT 0,0,CURRENT_TIMESTAMP,zasob) t WHERE id_zasobu=zasob ORDER BY czas ASC LIMIT 1 $$
LANGUAGE SQL;

natomiast ten union zostanie wywalony vide sugestia @jam231 i nie należy się na niego patrzeć (tj. należy obsługiwać przypadek gdy wywołanie zapytania nic nie zwróci)

marimarek commented 11 years ago

Ok, zjem i zaraz to zrobię.

Offtop: Nie macie może jakiejś prezentacji o testach modułowych albo jakiś inny temat z inżynieri oprogramowania? Już myślałem, że wygrałem 1 dzień życia, bo dostałem zajebistą prezentację o refaktoringu z NSNu, ale się okazało, że refaktoring już był na seminarium. :(

kaiks commented 11 years ago

:D ja nie mam, nie robiłem IO ani żadnego seminarium

jam231 commented 11 years ago

Ostatnia transakcja tez jest: m_cachedLastOrder Tyle tylko, że bez daty.

kaiks commented 11 years ago

Spojrzałem dopiero teraz po tym co @marimarek wrzucił

m_cachedLastOrder jest całkiem bez sensu LastOrder ma być ostatnim zrealizowanym zleceniem, czyli ostatnią transakcją. "LastOrder", niefortunnie nazwany (powinno być: LastTransaction, jak to było w jednym z moich powyższych komentarzy). W szczególności:

A teraz druga rzecz @marimarek sposób w jaki zaimplementowałeś GET_STOCKS_INFO jest niezgodny z napisaną przeze mnie specyfikacją

gdzie kazde z [pól] ma dwie wartosci: cena, ilosc

U Ciebie to ma tych pól dużo więcej. To jeszcze nie jest wielka zbrodnia, bo niby z podobną nadmiarowością już się godziliśmy (chociaż to według mnie niewygodne i brzydkie) natomiast nie wiem co się dzieje dla kodu:

    if(m_cachedBestBuyOrders.contains(stockId))
        bestBuyOrder = m_cachedBestBuyOrders[stockId];

w przypadku gdy klucza stockId nie ma. Tam są wartości domyślne które są zerami? Jeśli tak, to ok, ale to jest domyślanie się z mojej strony.

No i jak wyżej, obsługa lastOrder jest zła, ale to już wiadomo jaki jest problem z powyższego opisu.

kaiks commented 11 years ago

trochę rantowo i powtarzająco się mi to wyszło, jakoś ciężko mi się dziś myśli. Jeśli to co napisałem nie ma sensu to dajcie znać

marimarek commented 11 years ago

Opieralem sie glownie na tym, ze napisaliscie czego moge uzyc. Dlatego wyszlo jak wyszlo. Rozumiem, ze jesli maja byc tylko 2 parametry cena i ilosc to parametr ilosc moze byc zmergowany z kilku zlecen jesli sa po takiej samej cenie? W takim wypadku m_cachedBestBuyOrders i m_cachedBestSellOrders tez sie tutaj nie przydadza.

Jesli chodiz o watpliwosc co jesli nie ma zadnego zlecenia to te wartosci sa domyslnei incijalizowane domyslnym konstruktorem czyli zerami.

+    Order bestBuyOrder;
+    Order bestSellOrder;
+    Order lastOrder;
+
+    if(m_cachedBestBuyOrders.contains(stockId))
+        bestBuyOrder = m_cachedBestBuyOrders[stockId]; 

Nie wiem, kiedy bede cos w stanie jeszcze zrobic, ale na pewno nie wczesniej niz jutro w nocy i tego nie moge obiecac, bo we wtorek i czwartek mam seminarium + praca.

marimarek commented 11 years ago

Chociaz jesli parametr ilosc nie ma byc mergowany albo bede mial funkcje ktora wyciagnie dla najlepszych zlecen je z bazy danych to moge to poprawic w pracy. Tylko nie moge nawet obiecac, ze to sie skompiluje, bo nie mam jak tutaj tego sprawdzic.

marimarek commented 11 years ago

Chociaz jesli ma to byc w ten sposob po stornie serwera to mozna trzymac to tak:

QHash<qint32, QPair<qint32, qint32> > m_cachedBestSellOrders; 

i przy kazdym nadchodzacym zleceniu sprawdzac

if(m_cachedBestSellOrders.contains(stockId))
{
     if(cena < m_cachedBestSellOrders[stockId].first)
           m_cachedBestSellOrders[stockId] = qmake_pair(cena, ilosc);
     else if(cena == m_cachedBestSellOrders[stockId].first)
           m_cachedBestSellOrders[stockId].second += ilosc;
}
else
{
     m_cachedBestSellOrders[stockId] = qmake_pair(cena, ilosc);
}
QPair<qint32, qint32>

Zastaplibym tez jakas struktura szczegolnie, ze wykorzystywac bedziemy to nie raz

|A swoja droga teraz jest blad, bo w market.cpp:295 np.:

changeCachedBestSellOrders(userId);

, a ta funkcja oczekuje stockId, wiec jak widze na razie to te m_cached* chyab wogle nie dzialaja.

kaiks commented 11 years ago

dobra moze sam to naprawie jakos prymitywnie dzis jesli nie masz czasu

te cached buy/sell sa dobrze zrobione (poza tym ze niby 'nieoptymalnie'), tj. wyznaczane na podstawie: query.prepare("SELECT najlepsze_kupno(:stockId);");

co do bledu to chyba rzeczywiscie tam jest

kaiks commented 11 years ago

póki co przepchnąłem to na chama zamieniając order na qpair etc i poprawiając trochę lasttransaction (wcześniej lastorder), zaraz to przetestuję

nie wiem jaka jest umowa społeczna obecnie, więc wrzuciłem to na swojego brancha (co jest bez sensu wg mnie, bo i tak programujemy na danych plikach szeregowo a nie równolegle i powstaje zbędna biurokracja)

jam231 commented 11 years ago

Chwila, chwila, bo my się w takim razie nie zrozumieliśmy. LastOrder zmienia się również w sellStock i buyStock. Rozumiem, że teraz rzeczywiscie jest to troche bez sensu. Co chcemy dokladnie miec ? Ostatnia transakcje ? Ostatnie nadane zlecenie (do wysylania przy logowaniu) ? Dlaczego ostatnia transakcja bedzie sie zmieniala tylko poprze CHANGE_CHANNEL, a nie rowniez poprzez dwa inne przeciez one informuja o zrealizowaniu transakcji ?

kaiks commented 11 years ago

pewnie że ostatnie transakcje, przecież o tym mówiłem i wielokrotnie jasno się wyraziłem w tym issue że tego właśnie chce

change_channel nie informuje nas o id użytkowników bo to całkiem inna informacja, tam mamy informacje o tym, że transakcja jakaś się wykonała

w kanale o np. zleceniach kupna mamy informacje że dla użytkownika X i zlecenia Y (częściowo) zrealizowało się zlecenie, tj. informujemy go, żeby sobie w swoim kliencie zaktualizował stan jego zlecenia na nową ilość Z

no i kto tu pobieżnie czyta... ;)

A, i jeszcze jedna sprawa: moja implementacja jakośtam działa

jam231 commented 11 years ago

@marimarek Tam była "literówka" :-( poprawiam i wrzucam na repo. Jak bardzo chcesz zmieniać te część to proszę zrób to tak, żeby to jakoś wyglądąło - rozumiem niechęć częstego odwoływania się do bazy (bo to pewnie wolne), ale struktura o której mówiłeś już jest - BestOrder.

kaiks commented 11 years ago

ja to poprawiłem na swoim branchu już i tylko będą problemy z merge teraz chociaż ja się na tym nie znam

bestorder ma 4 pola a nasza struktura ma 2 (chyba)

marimarek commented 11 years ago

Jesli chodzi o merge to w zaleznosci co z czym chcesz mergow'ac. Jelsi chcesz miec na swoim branchu wszytko co na master + swoje zmiany to robisz tak:

git checkout dev_kaiks    --przelacza cie na Twoj branch
git merge master  --dodaje wszytko co da sie automatycznie zmergowac z mastera do Twojego brancha

o tym co sie nie da git cie poinformuje wtedy musisz wejsc w te pliki o ktorych Cie poinformowal i tam beda linijki w stylu

>>>>>>> HEAD
kod z Twojego brancha
=============
kod z brancha master
<<<<<<<< master

Te musisz recznei zedytowac tak, zeby bylo dobrze.

Pozniej dla kazdego takiego pliku dajesz

git add nazwa_pliku

poleceniem

git status

mozesz sprawdzic czy masz jakies zmiany niewkomitowane

kaiks commented 11 years ago

dzięki, dopiero to przeczytałem, następnym razem się zastosuję

Jako że w dalszym ciągu nikt się nie kwapi do wykazywania inicjatywy :japanese_ogre: to proponuję komuś implementacje prostej wiadomości CANCEL_ORDER ORDER_TYPE STOCK_ID być może z jakimś potwierdzeniem lub nie, malo wazne

po stronie bazy danych: DELETE FROM zlecenie_kupna WHERE id_zlecenia=... lub odpowiednio from zlecenie_sprzedazy

bo bez tego nie da się implementować panikowania o którym mówiliśmy na konsultacjach

kaiks commented 11 years ago

Struktura order znowu spektakularnie zawiodła (a @marimarek znowu nie doczytał specyfikacji :p ).

Ok, przyznaję, po części moja wina, bo tego nie napisałem tutaj. Niemniej:

Jak pisałem:

CREATE OR REPLACE FUNCTION zlecenia_uz(uz integer) RETURNS TABLE(typ integer, id_zlecenia integer, id_zasobu integer,ilosc integer, limit1 integer)
...

Natomiast Ty pisałeś

void GetMyOrdersRespMsg::addOrder(Order::OrderType m_transactionType, qint32 m_stockId, qint32 m_amount, qint32 m_price)

Jest tu pewnego rodzaju niezgodność, mianowicie jest to niezgodność denerwująca mnie przy debugowaniu mojego agenta.

W skrócie: mamy w getmyorders wysyłać typ, id_zlecenia, id_zasobu, ilosc, cena, Ty wysyłasz: typ, id_zasobu, ilosc, cena

zjadłeś id_zlecenia

niech to ktoś plz poprawi

jednocześnie oświadczam wam, że jutro (w środę) będę miał co najwyżej 6 godzin na pracę nad tym, a pojutrze co najwyżej dwie godziny, nie wiem jak się z tym czujecie, ale tak tylko mówię (w szczególności z obecnym tempem prac nie ma szans żebyśmy coś sensownego pokazali na czwartek)

przypominam też o powyższym komentarzu dot. anulowania zleceń

jam231 commented 11 years ago

Wszystkie zmiany sa na branchu experimental, czekaja na review - o godzinie ~16 robie merge'a na masterze. @kaiks: 1) Poprawiłem GetMyOdersRespMsg - powinno działać tak jak chcesz. Zrób review, to wszystko jest w 1 commicie, a nie rozwalone na kilka, więc powinno się w miarę mało uciążliwie sprawdzać. 2) Zrobiłem na razie coś innego: Zamiast |CANCEL_ORDER|ORDER_TYPE|STOCK_ID| jest| CANCEL_ORDER_REQ|ORDER_ID| Nie wydaje mi się, żeby ORDER_TYPE, STOCK_ID, USER_ID miałyby tworzyć nadklucz (mówiąc językiem baz danych). Być może miałeś na myśli ORDER_TYPE, ORDER_ID - wydaję mi się jednak, że to spora uciążliwość dla agenta w wypadku, gdy ORDER_ID JEDNOZNACZNIE określa dowolna transakcje. Rozumiem oczywiście, że mamy podział typów zleceń na osobne tabele, ale nie uważam, że powinniśmy przenosić tę ułomność na klientów.

kaiks commented 11 years ago

@2 masz oczywiście rację, moja pomyłka przejrzę jak wrócę

marimarek commented 11 years ago

A w BestOrderMsg i OrderMsg nie chcemy id_zlecenia?

jam231 commented 11 years ago

@marimarek w BestOrderMsg na pewno nie, bo ona jest wysyłana do subskrybentów, a oni (jako osoby trzecie) nie powinni mieć tej informacji. Co do OrderMsg to ona stanowi baze dla wariacji dot. zleceń - m.in. BestOrderMsg po niej dziedziczy. Można by oczywiście rozdzielić te dwie klasy, ale wtedy OrderMsg nie reprezentowałaby jakiegoś ogólnego zlecenia, tylko skierowane do zlecajacego, jako że tylko on powinien mieć mieć wiedze o id swoich zleceń.

kaiks commented 11 years ago

potencjalny kupiec nigdy nie potrzebuje ID zlecenia bo to przecież nie tak działa (przypomnę: wysyłasz po prostu cenę i ilość, a serwer ma sam o resztę zadbać) i ordermsg jest w pewnym sensie nadmiarowością

to rozwiązanie z makepair jest takie średnio ładne chyba, ale dobra, mnie już nie interesuje żeby było ładnie więc nie mam prawie zastrzeżeń do tego kodu


+    query1.prepare("DELET FROM zlecenie_kupna AS zk WHERE zk.id_zlecenia = :orderId AND zk.id_uz = :userId;");
+    query1.bindValue(":orderId", orderId);
+    query1.bindValue(":userId", userId);
+
+    query2.prepare("DELET FROM zlecenie_sprzedazy AS zs WHERE zs.id_zlecenia = :orderId AND zs.id_uz = :userId;");
+    query2.bindValue(":orderId", orderId);
+    query2.bindValue(":userId", userId); 

no delete chyba

no i jeszcze jedna, dość ważna chyba sprawa ... nie widzę plików cancelordermsg.h/cpp

jam231 commented 11 years ago

Naprawilem, robie merge'a. Zdaje sobie sprawe, ze średnio ładne... ale ;-P

kaiks commented 11 years ago

przetestuję, dam znać i zamknę ten issue

następne problemy będą w osobnych (a te stare typu "coding style" etc chyba też można zamknąć?)

jam231 commented 11 years ago

Możesz je zamknąć jako, że przed wakacjami nic z nimi nie zrobimy.

kaiks commented 11 years ago

chyba po moich paru poprawkach działa, przy czym to chyba jest dość wątpliwe, bo już nie mam siły nad tym siedzieć