static void RunBid(Job job) { //Grab the total stocks the market maker owns of this stock int NumberOfStocksOwned = DataBaseHandler.GetCount("SELECT SUM(Quantity) FROM Inventories WHERE UserID = " + clientID + " AND StockName = '" + job.bidAndOffer.StockName + "'"); //Count how many of these the market maker is already selling int AlreadySelling = DataBaseHandler.GetCount("SELECT COUNT(Quantity) FROM Pool WHERE Type = 1 AND User = "******" AND StockName = '" + job.bidAndOffer.StockName + "'"); //Calculate the total stock available for the market maker to sell int StocksAvailable = NumberOfStocksOwned - AlreadySelling; //If it has more stock available than needed to complete the job if (job.Quanity <= StocksAvailable) { BidsAndOffers offer = new BidsAndOffers(true, DateTime.Now, job.bidAndOffer.Price, clientID, job.bidAndOffer.StockName, job.Quanity, 0); //Complete the trade by selling the market makers stock to this user TradeManager.CreateTrade(ref offer, ref job.bidAndOffer, job.Quanity, threadDataBaseHandler); //Remove job as it now complete Queue.Remove(job); } else { //Market maker does not have enough stock to currently complete this trade so it sells to job as much as it can and puts in a bid into the market to buy more //of the stock so that it can fully complete the job double Price = DataBaseHandler.GetCountDouble("SELECT SUM(CurrentPrice) FROM Stock WHERE StockName = '" + job.bidAndOffer.StockName + "'"); DataBaseHandler.SetData(string.Format("INSERT INTO Pool (Type, Price, User, StockName, Quantity) VALUES ({0}, {1}, {2}, '{3}', {4})", (int)BidOffer.bid, Math.Round(Price, 2) + 1.5, clientID, job.bidAndOffer.StockName, job.Quanity - StocksAvailable)); //Console.WriteLine(job.Quanity - StocksAvailable); BidsAndOffers offer = new BidsAndOffers(true, DateTime.Now, job.bidAndOffer.Price, clientID, job.bidAndOffer.StockName, StocksAvailable, 0); TradeManager.CreateTrade(ref offer, ref job.bidAndOffer, job.Quanity - StocksAvailable, threadDataBaseHandler); } }
void FIFO(ref BidsAndOffers Bid, ref List <BidsAndOffers> Offers) { //FIFO round simple assigns all remain bids and offers in a First in First Out approach Offers.OrderBy((o) => o.TimePlaced); for (int i = 0; i < Offers.Count; i++) { if (Bid.Quantity == 0) { break; } if (Offers[i].Quantity == 0) { continue; } if (Offers[i].Quantity > Bid.Quantity) { BidsAndOffers Offer = Offers[i]; TradeManager.CreateTrade(ref Bid, ref Offer, Bid.Quantity, threadDataBaseHandler); Offers[i] = Offer; } else { BidsAndOffers Offer = Offers[i]; TradeManager.CreateTrade(ref Bid, ref Offer, Offer.Quantity, threadDataBaseHandler); Offers[i] = Offer; } } }
private void LMMRound(ref BidsAndOffers Bid, ref List <BidsAndOffers> Offers) { //In the LLM round we assign a selection of all bids at the price level to lead market makers, this help market makers complete orders faster for (int i = 0; i < Offers.Count; i++) { //Select their LMM percentage from DB MySqlDataReader r = threadDataBaseHandler.GetData("SELECT LMM FROM Users WHERE ID = " + Offers[i].User); double LMMPercentage = 0; while (r.Read()) { LMMPercentage = (double)r["LMM"]; } //Check if they have a percentage if (LMMPercentage > 0f) { int LMMAmount = (int)(Bid.Quantity * LMMPercentage); if (LMMAmount > 0) { //If there percentage is more than avilable we clamp it to max if (LMMAmount > Offers[i].Quantity) { BidsAndOffers Offer = Offers[i]; TradeManager.CreateTrade(ref Bid, ref Offer, Offer.Quantity, threadDataBaseHandler); Offers[i] = Offer; } else { BidsAndOffers Offer = Offers[i]; TradeManager.CreateTrade(ref Bid, ref Offer, LMMAmount, threadDataBaseHandler); Offers[i] = Offer; } } } } }
public static void RemoveFromPool(BidsAndOffers Trade, ThreadDataBaseHandler threadDataBaseHandler) { //When a bid or offer is ready to be removed it passed to this method which removes it from DB string command = string.Format("DELETE FROM Pool WHERE Type = {0} AND TimePlaced = '{1}' AND Price = {2} AND User = {3} AND StockName = '{4}'", Trade.Type, Trade.TimePlaced.ToString("yyyy-MM-dd HH:mm:ss"), Trade.Price, Trade.User, Trade.StockName); threadDataBaseHandler.SetData(command); threadDataBaseHandler.CloseCon(); }
static void RunOfffer(Job job) { //Purchase the stocks that this job is selling to complete the job BidsAndOffers bid = new BidsAndOffers(false, DateTime.Now, job.bidAndOffer.Price, clientID, job.bidAndOffer.StockName, job.Quanity, 0); TradeManager.CreateTrade(ref job.bidAndOffer, ref bid, job.Quanity, threadDataBaseHandler); //Remove job from queue as it is now complete Queue.Remove(job); }
public static void CreateTrade(ref BidsAndOffers Bid, ref BidsAndOffers Offer, int Quantity, ThreadDataBaseHandler threadDataBaseHandler) { //Get the total quantity that the user can sell int StockAvailable = threadDataBaseHandler.GetCount(string.Format("SELECT COUNT(Quantity) FROM Inventories WHERE StockName = '{0}' AND UserID = {1}", Offer.StockName, Offer.User)); if (Quantity > StockAvailable) { //If the quantity if the sale is greater than that the user can offer limit to the max amount the user could sell Quantity = StockAvailable; } //If the Quantity is not greater than one we can skip trade creation if (Quantity > 0) { //Checking to see if the bid user has an entry in the iventory table if (threadDataBaseHandler.GetCount("SELECT COUNT(UserID) FROM Inventories WHERE UserID = " + Bid.User + " AND StockName = '" + Bid.StockName + "'") == 0) { //If not then an entry for the bid user for this stock is inserted into inventories threadDataBaseHandler.SetData(string.Format("INSERT INTO Inventories(UserID, StockName, Quantity, LastTradedPrice) VALUES({0}, '{1}', {2}, {3})", Bid.User, Bid.StockName, 0, 0)); } //Update the database reflect the new trade threadDataBaseHandler.SetData(string.Format("INSERT INTO Trades(StockName, BuyerID, SellerID, Price, Quantity) VALUES('{0}', {1}, {2}, {3}, {4})", Bid.StockName, Bid.User, Offer.User, Offer.Price, Quantity)); threadDataBaseHandler.SetData(string.Format("UPDATE Inventories set LastTradedPrice = {0}, Quantity = Quantity - {1} WHERE StockName = '{2}' AND UserID = {3}", Offer.Price, Quantity, Offer.StockName, Offer.User)); threadDataBaseHandler.SetData(string.Format("UPDATE Inventories set LastTradedPrice = {0}, Quantity = Quantity + {1} WHERE StockName = '{2}' AND UserID = {3}", Offer.Price, Quantity, Offer.StockName, Bid.User)); threadDataBaseHandler.SetData(string.Format("UPDATE Stock SET VolumeTraded = VolumeTraded + {0} WHERE StockName = '{1}'", Quantity, Offer.StockName)); threadDataBaseHandler.SetData(string.Format("UPDATE Users SET Balance = Balance + {0} WHERE ID = {1}", Offer.Price * Quantity, Offer.User)); threadDataBaseHandler.SetData(string.Format("UPDATE Users SET Balance = Balance - {0} WHERE ID = {1}", Offer.Price * Quantity, Bid.User)); } else if (Quantity < 0) { throw new Exception("Error with trade, quantity is less than 0"); } //Checking if trade went ahead if (Quantity != 0) { //If it did then we are updating are local version of the bids and offfers in the server pool //This allows the matchmaking algorythim to continue without having to grab the new trade data //from the database Bid.Quantity -= Quantity; Offer.Quantity -= Quantity; //Update database to reflect new trade threadDataBaseHandler.SetData(string.Format("Update Pool set Quantity = {0} WHERE Type = {1} AND TimePlaced = '{2}' AND Price = {3} AND User = {4} AND StockName = '{5}'", Bid.Quantity, Bid.Type, Bid.TimePlaced.ToString("yyyy-MM-dd HH:mm:ss"), Bid.Price, Bid.User, Bid.StockName)); threadDataBaseHandler.SetData(string.Format("Update Pool set Quantity = {0} WHERE Type = {1} AND TimePlaced = '{2}' AND Price = {3} AND User = {4} AND StockName = '{5}'", Offer.Quantity, Offer.Type, Offer.TimePlaced.ToString("yyyy-MM-dd HH:mm:ss"), Offer.Price, Offer.User, Offer.StockName)); } else { //If they couldn't supply any stock to sell then set the offer quantity to be zero Offer.Quantity = 0; } //Close the connection to the DB so that DB connection thread can be open for the next thread threadDataBaseHandler.CloseCon(); }
void ProRataWithLMM(ref BidsAndOffers Bid, ref List <BidsAndOffers> Offers, int ProRataMinimumAllocation) { //This round assigns offer quantities in relation to the size of the pool int TotalQuanityOfOffers = 0; int BidQuanity = Bid.Quantity; foreach (BidsAndOffers o in Offers) { TotalQuanityOfOffers += o.Quantity; } for (int i = 0; i < Offers.Count; i++) { double ProRata = 0; if (Offers[i].Quantity != 0) { //This equation gives us the percentage of the total quantity of offer this offer is ProRata = (double)Offers[i].Quantity / (double)TotalQuanityOfOffers; } int ProRataAmount = (int)(ProRata * BidQuanity); //This stop there being a lower amount of stock moved if small value //Could increase this value to stop small trades of only 1 stock ect being assigned if (ProRataAmount >= ProRataMinimumAllocation) { if (ProRataAmount > Offers[i].Quantity) { BidsAndOffers Offer = Offers[i]; TradeManager.CreateTrade(ref Bid, ref Offer, Offer.Quantity, threadDataBaseHandler); Offers[i] = Offer; } else { BidsAndOffers Offer = Offers[i]; TradeManager.CreateTrade(ref Bid, ref Offer, ProRataAmount, threadDataBaseHandler); Offers[i] = Offer; } } } }
//This is called by pool and it simply creates a new instance of Job class //which takes the bid / offer which has been taken from the DB to be completed //by the market maker as it had been in the pool too long. //This instance of Job is then added to Queue public static void AddJob(BidsAndOffers bidAndOffer) { Queue.Add(new Job((JobType)Convert.ToInt32(bidAndOffer.Type), bidAndOffer)); }
public Job(JobType jobType, BidsAndOffers bidAndOffer) { this.jobType = jobType; this.bidAndOffer = bidAndOffer; }
public async void RunMatchMaker(string s, int ThreadCounter) { //Store DB connection class from array in Pool in order to not overload the server with conncetions threadDataBaseHandler = Pool.DataBaseHandlers[ThreadCounter]; //Get the Pricelevels of bids for the assigned stock from DB MySqlDataReader BidPoolReader = threadDataBaseHandler.GetData("SELECT DISTINCT Price FROM Pool WHERE Type = 0 AND StockName = '" + s + "' ORDER BY Price ASC"); List <double> BidPriceLevels = new List <double>(); while (BidPoolReader.Read()) { //Read redsults from DB BidPriceLevels.Add((double)BidPoolReader["Price"]); } if (BidPriceLevels.Count == 0) { return; } //Get the Pricelevels of offers for the assigned stock from DB MySqlDataReader OfferPoolReader = threadDataBaseHandler.GetData("SELECT DISTINCT Price FROM Pool WHERE Type = 1 AND StockName = '" + s + "' ORDER BY Price DESC"); List <double> OfferPriceLevels = new List <double>(); while (OfferPoolReader.Read()) { //Read redsults from DB OfferPriceLevels.Add((double)OfferPoolReader["Price"]); } if (OfferPriceLevels.Count == 0) { return; } //Close connection with DB threadDataBaseHandler.CloseCon(); foreach (double BidPrice in BidPriceLevels) { for (int i = 0; i < OfferPriceLevels.Count; i++) { //Cycle through the bid price levels with every offer price level to find offers which are lower than that of the bid price level if (OfferPriceLevels[i] <= BidPrice) { //if this is the case then lets grab all the bids at this level to be able to assign with offers at this price level MySqlDataReader BidReader = threadDataBaseHandler.GetData("SELECT * FROM Pool WHERE Type = 0 AND StockName = '" + s + "' AND Price = " + BidPrice); List <BidsAndOffers> bids = new List <BidsAndOffers>(); while (BidReader.Read()) { //These are commented out as they are used for debugging //Console.WriteLine(BidReader["Type"].GetType()); //Console.WriteLine(BidReader["TimePlaced"].GetType()); //Console.WriteLine(BidReader["Price"].GetType()); //Console.WriteLine(BidReader["User"].GetType()); //Console.WriteLine(BidReader["StockName"].GetType()); //Console.WriteLine(BidReader["Quantity"].GetType()); //Console.WriteLine(BidReader["TurnsInPool"].GetType()); bids.Add(new BidsAndOffers((bool)BidReader["Type"], (DateTime)BidReader["TimePlaced"], (double)BidReader["Price"], (int)BidReader["User"], (string)BidReader["StockName"], (int)BidReader["Quantity"], (int)BidReader["TurnsInPool"])); } //Grab the offers at this price level for assignment MySqlDataReader OfferReader = threadDataBaseHandler.GetData("SELECT * FROM Pool WHERE Type = 1 AND StockName = '" + s + "' AND Price = " + OfferPriceLevels[i]); List <BidsAndOffers> offers = new List <BidsAndOffers>(); while (OfferReader.Read()) { offers.Add(new BidsAndOffers((bool)OfferReader["Type"], (DateTime)OfferReader["TimePlaced"], (double)OfferReader["Price"], (int)OfferReader["User"], (string)OfferReader["StockName"], (int)OfferReader["Quantity"], (int)OfferReader["TurnsInPool"])); } //While there is atleast one offer and one bid available at this price range we allocate them while (bids.Count != 0 && offers.Count != 0) { BidsAndOffers b = bids[0]; LMMRound(ref b, ref offers); #region Cleaner foreach (BidsAndOffers o in offers) { if (o.Quantity <= 0) { TradeManager.RemoveFromPool(o, threadDataBaseHandler); } } offers.RemoveAll((o) => o.Quantity <= 0); bids[0] = b; if (bids[0].Quantity <= 0) { TradeManager.RemoveFromPool(bids[0], threadDataBaseHandler); bids.RemoveAt(0); continue; } #endregion ProRataWithLMM(ref b, ref offers, 5); #region Cleaner foreach (BidsAndOffers o in offers) { if (o.Quantity <= 0) { TradeManager.RemoveFromPool(o, threadDataBaseHandler); } } offers.RemoveAll((o) => o.Quantity <= 0); bids[0] = b; if (bids[0].Quantity <= 0) { TradeManager.RemoveFromPool(bids[0], threadDataBaseHandler); bids.RemoveAt(0); continue; } #endregion FIFO(ref b, ref offers); #region Cleaner foreach (BidsAndOffers o in offers) { if (o.Quantity <= 0) { TradeManager.RemoveFromPool(o, threadDataBaseHandler); } } offers.RemoveAll((o) => o.Quantity <= 0); bids[0] = b; if (bids[0].Quantity <= 0) { TradeManager.RemoveFromPool(bids[0], threadDataBaseHandler); bids.RemoveAt(0); continue; } #endregion } } } } threadDataBaseHandler.CloseCon(); }