Closed kaiks closed 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
Przychylam się do prośby o zmiane nazwy na NEW_ORDER.
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.
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)
zrób ktoś obsługę GetStocks i GetOrder :(
Lamentuj... Ja będę mógł się za to wziąć za jakieś.. 2-3h
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
Marek na swojej gałęzi dodał funkcjonalności GetMyStocks oraz GetMyOrders, które jakośtam działają
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
A jest coś do tego po stronie bazy? Jak tak to w serwerze ja to mogę zrobić.
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)
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. :(
:D ja nie mam, nie robiłem IO ani żadnego seminarium
Ostatnia transakcja tez jest:
m_cachedLastOrder
Tyle tylko, że bez daty.
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.
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ć
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.
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.
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.
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
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)
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 ?
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
@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.
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)
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
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
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ń
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.
@2 masz oczywiście rację, moja pomyłka przejrzę jak wrócę
A w BestOrderMsg i OrderMsg nie chcemy id_zlecenia?
@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ń.
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
Naprawilem, robie merge'a. Zdaje sobie sprawe, ze średnio ładne... ale ;-P
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ąć?)
Możesz je zamknąć jako, że przed wakacjami nic z nimi nie zrobimy.
chyba po moich paru poprawkach działa, przy czym to chyba jest dość wątpliwe, bo już nie mam siły nad tym siedzieć
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