wtorek, 30 października 2018

Giełda - pBuySell - dodanie funkcjonalności cz1

Procedura pBuyStock
Zmniejszenie ilości parametrów  wersji dotychczasowej były:

  • @stockName varchar(10) - nazwa akcji która wystąpi w zleceniu kupna i sprzedaży,
  • @user_id int - interesujemy się portfelem użytkownika,
  • @mark_id int - rekord na rynku akcji,
  • @stockCountBuy int - ilość akcji do kupienia

Po zmianie procedury chcę otrzymać globalną procedurę która pozwoli mi "przejechać" po rynku i wykonać zlecenia kupno/sprzedaż.
Rozwiązania:

  1. Pozostawiam w parametrze tylko nazwę akcji, przy wywołaniu procedury korzystam z  kursora którym wyszukuje tylko aktywne zlecenia sprzedaży, aktywne to takie, których termin ważności się nie skończył, zakładam, że procedura sprawdzania daty ważności zleceń wykonała się wcześniej (aczkolwiek powinienem mieć dodatkową table z etapami, w których wpisuje rozpoczęcie -> zakończenie procedury sprzątania rynku ??-> bonowato, w takiej tabeli info o stanie wykonania procedury powinno się znaleźć). Na początku biorę zlecenia po każdej cenie gdyż nie muszę sprawdzać ceny akcji w rekordach na rynku, a jedynie cenę  ostatniej transakcji  w tabeli Stock. Owszem istnieje opcja, że wyszukam  na początku zlecenia, które mają taką samą cenę jaka jest w tabeli Stock, tu mam dylemat nie wiem, która opcja jest lepsza. Na początek kPKC czyli kupno po każdej cenie. Wyszukuje zlecenia odnoszące się do danej akcji oraz w statusie kPKC oraz bs_id = 2 lub 4. Tu jest jeszcze jedna uwaga jeżeli cenę kupna sprzedaży ustalam to muszę ją wziąć nie z globalnej tabeli Stock,a ze zleceń sprzedaży gdyż cena sprzedaży również jest ustalana.
Pytania do powyższego:
  • Czy najpierw zlecenie kPKC czu kCU?
  • Jeżeli mam zlecenia kPKC to jaka jest kolejność ich realizacji?
  • Po jakiej cenie ma być kupno?
  • Czy cena ma być brana z zleceń sprzedaży lub emisji, czy z tabeli stock?
  • Jaka jest kolejność zleceń sprzedaży branych pod uwagę przy realizacji zleceń kupna, chodzi o cenę akcji?
  • Czy cena akcji w tabeli stock powinna być wyznacznikiem (odniesieniem) dla kursu (kupna sprzedaży) danej akcji?
Stwierdzenia:
  • Zlecenia należy grupować według daty ich utworzenia,
  • Minimalny okres "życia" akcji mogę ustalić na jeden dzień, w moim przypadku na godzinę (np),
  • Wartość akcji minimalna i maksymalna ustawiana na podstawie bieżącego kursu z uwzględnieniem +20% dla maksymalnej wartości i -20% dla minimalnej wartości.
Wyzwania:
  • ustalenie ceny po jakiej ma być dokonana transakcja dla zleceń kPKC oraz sPKC, jak się okazuje transakcje  kupno po każdej cenie są trudniejsze do zrobienia,
Transakcje z ceną ustaloną:
  1. Sprawdzam czy na rynku są zlecenia kupna danej akcji, opcja druga to nie sprawdzam rynku pod kątem nazw akcji tylko daty emisji zlecenia kupna, a jeżeli są dwa lub więcej zleceń o tej samej dacie to wybieram te które jest na wyższą ilość akcji do kupienia.Opcja druga lepsza.
  2. Mam już zlecenie uchwycone, sprawdzam czy cena w zleceniu jest taka sama jak cena akcji w tabeli stock - czyli cena ostatniej udanej transakcji. Tu jest uwaga co z ceną która jest wpisana w zleceniu sprzedaży czy mam ją brać pod uwagę? Można by patrzeć pod kątem, Pobieram zlecenia tylko te w któych cena kupna jest taka sam po stronie kupna sprzedaży, kPKC to patrze jeszcze dodatkowo na cenę w tabeli stock.
  3. Co do transakcji kPKC (wczoraj wieczorem wpadłem na pomysł) nie mam ustawionej ceny akcji w zleceniu biorę wtedy cenę z ostatniej dokonanej transakcji czyli cenę z tabeli stock ale dziś mi się przypomniało po każdej cenie oznacza że muszę wziąśc również transakcje z ceną ustaloną i  stamtąd brać cenę więc jeżeli mam po każdej cenie to biorę pod uwagę wszystkie transakcje sprzedaży i te sCU i te sPKC, jeżeli nie ma ceny w zleceniu to biorę cenę z tabeli stock, a jeżeli jest to z zelecenia.

poniedziałek, 29 października 2018

Giełda - procedura kupno-sprzedaż rozbudowa, założenia

Rozszerzenie procedury o status ceny,  do tej pory ustalenie ceny kupna akcji polega na tym, że szukam zleceń sprzedaży (jeżeli nie ma sprzedaży, kupna też nie da się wykonać) określonej akcji, w rekordzie na rynku dotyczącym sprzedaży lub emisji jest cena oraz ilość(sztuk) akcji do sprzedaży, na tej podstawie określam wartość transakcji.
Uznałem, że to dobry czas na zmianę póki procedura nie jest jeszcze tak skomplikowana. Cena zostanie określona na podstawie ceny w zleceniu kupna i porównanie jej do zlecenia sprzedaży lub emisji jeżeli ceny będą równe odbędzie się transakcja kupna, jeżeli cena się nie zgadza to zlecenie czeka aż cena zostanie osiągnięta. Tutaj pojawi się status ceny tzn.:

  • kPKC - kupuj po każdej cenie, 
  • sPKC - sprzedaj po każdej cenie,
  • kCU - kupuj cena ustalona,
  • sCU  - sprzedaj cena ustalona.
Wprowadzenia daty i czasu ważności zlecenia było by mile widziane, aczkolwiek łączy się to z dodatkowym nakładem pracy w procedurze kupna/sprzedaży, która to funkcjonalność będzie musiała sprawdzać czy dane zlecenie jest ważne i środki "zamknięte" w zleceniu zostaną zwrócone. Takie rozwiązanie pasowało by na funkcje która na początku procedury patrzy po rynku i wyszukuje zleceń które straciły ważność. Opcja druga to osobna procedura, która przeszukuje rynek niezależnie od procedury będzie uruchamiana przed uruchomieniem procedury kupno/sprzedaż.

Schemat bazy danych po wprowadzeniu dodatkowej tabeli.




wtorek, 23 października 2018

Giełda - implementacja repozytorium MarketSquareDataSource

Aplikacja posiada trzy projekty:
  • Repozytorium
  • UnitTesty
  • MVC
Założeniem jest stworzenie repozytorium w którym będzie zbudowany model danych w oparciu o entity framework. Dodatkowo widoki z ms sql-a będą odwzorowane w klasach gdyż EF nie radzi sobie z widokami bez klucza głównego (albo czegokolwiek co go przypomina). Dodatkowo chce żeby cała logika aplikacji "siedziała" w repozytorium. Aplikacja MVC będzie się łączyć z repo za pomocą interfejsów.
Założeniem moim jest aby każde zapytanie o jakiekolwiek dane było kierowane do repozytorium poprzez interfejs.
MarketSquareDataSource 

public interface IMarketSquareDataSource
    {
       IEnumerable<MarketSquareDataSource> viewAllStockInMarketSquare();
    }

    public class MarketSquareDataSource : IMarketSquareDataSource
    {
        public string stockName;
        public int stockNumber;
        public decimal? stockPriceBuy;
        public decimal? stockPriceSell;
        public string transactionStatus;
        public int marketS_id;
        public bool transactionActive;
        public string stockSeria;
        public int stockId;

        public IEnumerable<MarketSquareDataSource> viewAllStockInMarketSquare()
        {
            using (var db = new StockExchangeEntities())
            {
                var result = db.MarketSquare.Join(db.BuyingSelling,
                    MS => MS.bs_id,
                    BS => BS.bs_id,
                    (MS, BS) => new
                    {
                     transactionStatus = BS.bs_action,
                     marketS_id = MS.mark_id,
                     stockPriceBuy = MS.mark_sharePriceBuy,
                     stockPriceSell = MS.mark_sharePriceSell,
                     stock_id = MS.stock_id,
                     stockNumber = MS.mark_numberOfShares,
                     transactionActive = MS.mark_aktywny
                    }).Join(db.Stock,
                    MS => MS.stock_id,
                    St => St.stock_id,
                    (MS, St) => new
                    {
                     transactionStatus = MS.transactionStatus,
                     marketS_id = MS.marketS_id,
                     stockPriceBuy = MS.stockPriceBuy,
                     stockPriceSell = MS.stockPriceSell,
                     stock_id = MS.stock_id,
                     stockNumber = MS.stockNumber,
                     transactionActive = MS.transactionActive,
                     stockN_id = St.stockN_id,
                     stockSeria = St.stock_seria
                    }).Join(db.StockName,
                    MS => MS.marketS_id,
                    SN => SN.stockN_id,
                    (MS,SN) => new MarketSquareDataSource
                    {
                    transactionStatus = MS.transactionStatus,
                    marketS_id = MS.marketS_id,
                    stockPriceBuy = MS.stockPriceBuy,
                    stockPriceSell = MS.stockPriceSell,
stockNumber = MS.stockNumber == null ? 0 : (int)MS.stockNumber,    transactionActive = MS.transactionActive == null ? false : (bool)MS.transactionActive,
                    stockName = SN.stockN_name,
                    stockSeria = MS.stockSeria,
                    stockId = MS.stock_id == null ? 0 : (int)MS.stock_id
                    }).AsEnumerable();
                return result;
            }
        }
    }

sobota, 20 października 2018

Giełda - założenia

Na początku były przemyślenia dotyczące tego jak powinna funkcjonować moja giełda, gdy za czołem pisać procedury pewne założenia uległy zmianie, inne zostały rozszerzone o nowe funkcjonalności. (Schematów bazy było co najmniej 5).

Schemat bazy numer 1

Kupno akcji
  1.  nowa pozycja na rynku, kupno ustawiam status bs_id na 1 = kupno, podaje ilość akcji do kupienia i cenę, 
  2. sprawdzam ilość dostępnych akcji w tabeli stock i cenę, 
    1. jeżeli cena jest niższa lub wyższa to sprawdzam czy ktoś w takiej cenie  chce sprzedać (kolumna sharePriceSell), jeżeli chce to puszczam na rynek, zmieniam status pozycji na rynku na bs_id = 0, zmniejszam ilość akcji  w tabeli stock aktualizuje cenę na podstawie ceny z transakcji (kolumna sharePriceBuy) oraz dopisuje datę aktualizacji w tabeli stock, zmniejszam ilość kasy w portfelu oraz zwiększam ilość nabytych akcji (kolumna może być niepotrzebna, możliwe że kolumna do weryfikacji w razie przekłamań),
    2. jeżeli nikt nie sprzedaje w takiej cenie, opcje są dwie albo ustawienie statusu oczekiwanie jeżeli cena spadnie lub się podniesie i zamrożenie środków, albo info zwrotne do użytkownika że transakcja nie możliwa musi zmienić cenę (pierwsza opcja ciekawsza)
Sprzedaż akcji

  1. mam pozycję na rynku (w portfelu), sprawdzam czy na rynku są akcje ilość i cena i teraz jeżeli:
    1.  np chcę sprzedać 100 akcji  po danej cenie, a jest oferta na 50 akcji o tej cenie i 50 po niższej to co wtedy? - albo brak zgody albo podzielenie oferty na dwa, czyli brak zgody
    2. na rynku nikt nie chce sprzedawać, ale mam emitenta  w tej tabeli jest pewna ilość - więc ściągam ilość zmieniam cenę jeżeli jest inna, zeruje tabele akcje ilość min = 0, wszystkie akcje w rynku, zmieniam status transakcji na bs_id = 0
  2. jeżeli transakcja doszła do skutku kasa w portfelu rośnie, ilość akcji w portfelu maleje, ilość akcji u innych użytkowników maleje i/lub u emitenta, cena rynkowa ustalona u emitenta w tabeli stock na cenę ostatniej sprzedaży aktualizacja daty w tabeli stock, 
Emisja

  1. Emitent wysyła pakiet akcji na rynek rekord w tabeli rynek z pustym polem portfel (null), wypełniona tylko cena sprzedaży, cena skupu = 0, status bd_id = 2, ilość w tabeli stock zmniejszona o ilość akcji na rynku lub zjazd do zera jeżeli wszystkie są w rynku, jeżeli ilość akcji w tabeli stack to ilość akcji na rynku to pilnuje tylko żeby nie przekroczyć limitu stackMaxCount, opcja dodatkowa na przyszłość parametr cena akcji jeżeli jest równa zero to pobieram cenę z tabeli stock, jeżeli nie to wpisuje nową cenę do emisji w tabeli marketsquare .
Aktualizacja do Kupna jeżeli jest emisja to patrze też na akcje nie przypisane do nikogo.
Cena w tabeli Stock może być ceną średnią na rynku lub najwyższą w sprzedaży, aczkolwiek można by się zastanawiać czy w ogóle powinna istnieć ta kolumna.

Skup
  1. Rekord w tabeli rynek z pustym polem portfel, cena sprzedaży = 0, uzupełniona cena skupu na podstawie ceny z tabeli Stock (?), status bd_id = 1, ilość akcji  = 0, a wraz z trwaniem skupu ilość się zwiększa nie może przekroczyć maksymalnej ilości wyemitowanych akcji. Zakończenie skupu to status bd_id = 0.
Cykl giełdy
???

Tabela BuyingSelling wartości:
  • 0 - brak akcji,
  • 1 - kupno,
  • 2 - sprzedaż
W wersji kolejnej Tabela ze statusami wygląda następująco:

  1. nothing happend
  2. buy
  3. sell
  4. emission
  5. return

Procedury (zachowanie  funkcjonalności) były testowane za pomocą managmenta, gdyż interfejs jeszcze nie powstał. Przewiduje że strona będzie oparta o ASP.net MVC, do łatwiejszego wyświetlania zastosje Enity Framwerok, repozytorium będzie w osobnym projekcie do którego dostęp będzie za pomocą interfejsów, kontrolery będą służyć tylko do wyświetlenia danych na widoku cała logika w repozytroium

Giełda - Procedura emisji


procedure [dbo].[pStockEmission](
@id_stock int,
@setNumberStocks int,
@setStockPrice money
) as

begin
declare @getnumberOfStocks int
declare @stocksPrice money
declare @maxStockCount int
declare @TransactionPrice money
if(@setStockPrice > 0)
begin
set @stocksPrice = @setStockPrice
end
else
begin
select @stocksPrice = stock_pricie from Stock where stock_id = @id_stock and stock_aktywny = 1
end
--ilosc akcji w rynku
select @getnumberOfStocks = stock_count,@maxStockCount = stock_maxCount
from Stock
where
stock_id = @id_stock
if((@getnumberOfStocks + @setNumberStocks) <= @maxStockCount)
begin
--kwota transakcji
set @TransactionPrice = @setNumberStocks * @stocksPrice
--rozpoczecie emisji
print 'insert'
INSERT INTO [dbo].[MarketSquare]
([stock_id],[wal_id],[mark_numberOfShares],[mark_aktywny]
,[mark_sharePriceBuy],[bs_id],[mark_sharePriceSell],[mark_dataStart],[mark_dataEnd],[ mark_TransactionPrice])
VALUES (@id_stock,null,@setNumberStocks,1,0,4,@stocksPrice,GETDATE(),null,@TransactionPrice)
Update Stock set
stock_count = @getnumberOfStocks + @setNumberStocks,
stock_date = GETDATE()
where
stock_id = @id_stock
print @getnumberOfStocks + @setNumberStocks
end
else
begin
print 'ilosc akcji do emisji za duża'
end
end

Giełda - tworzenie zlecenia (transakcji) sprzedaży


parametry
@user_id int,
@numberSellStock int,
@stock_name varchar(10)

--pomocnicze
declare @wallet_id int
declare @stock_id int
declare @stockN_id int
declare @stockPrice money
--wyszukanie portfela oraz akcji
select @wallet_id = wal_id from UserTable where usr_id =@user_id
select @stockN_id = stockN_id from StockName where stockN_name = @stock_name
select @stock_id = stock_id, @stockPrice = stock_pricie from Stock where stockN_id = @stockN_id
--wyuszukanie akcji uzytkownika, stan 'brak akcji' oraz ze zostaly zakupione 
mark_transaction = 0
declare @countStockInWallet int
declare @countStockInmarket int
select @countStockInmarket = sum(mark_numberOfShares) from MarketSquare where stock_id = @stock_id and wal_id = @wallet_id and bs_id = 1
select @countStockInWallet = wal_numberOfShares from Wallet where wal_id = @wallet_id
if(@numberSellStock <= @countStockInmarket)
begin
--transakcja na rynek
INSERT INTO [dbo].[MarketSquare]
([stock_id],[wal_id],[mark_numberOfShares]
,[mark_aktywny],[mark_sharePriceBuy]
,[bs_id],[mark_sharePriceSell]
,[mark_dataStart],[mark_TransactionPrice])
VALUES
(@stock_id,@wallet_id,@numberSellStock,1,0,3,@stockPrice,GETDATE(),0)
--update portfela zmniejszenie ilosc akcji
declare @resultStock int
set @resultStock = @countStockInWallet - @numberSellStock
print 'ilosc akcji po wystawienu na sprzedaz => ' + CAST(@resultStock as varchar)
update Wallet set
wal_numberOfShares = @resultStock
where
wal_id = @wallet_id
end
else
begin
print 'za mało akcjki w portfelu, zmniejsz liczbe'
end
END

 Po wielu miesiącach przerwy Czteroletnim exodusie do bloga ismartdev, który zdechł w zeszłym roku w listopadzie, na powrót wstąpiłem w ten ...