public async Task <bool> SellStock(UserStocks stock, decimal price) { var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == stock.UserId); UserStocks checkingStock = await _context.UserStocks.Where(us => us.UserId == stock.UserId && us.CompanyCode == stock.CompanyCode).FirstOrDefaultAsync(); if (checkingStock == null) { throw new Exception("You do not have any units of this company"); } var stockExchnage = await _context.Users.FirstOrDefaultAsync(u => u.Username.ToLower() == Extensions.STOCK_EXCHANGE); var stockExchnageStocks = await _context.UserStocks.FirstOrDefaultAsync(us => us.UserId == stockExchnage.Id && us.CompanyCode == stock.CompanyCode); stockExchnageStocks.OwnedUnits += stock.OwnedUnits; if (stock.OwnedUnits > checkingStock.OwnedUnits) { throw new Exception("You have too few units"); } else if (stock.OwnedUnits == checkingStock.OwnedUnits) { _context.UserStocks.Remove(checkingStock); } else { checkingStock.OwnedUnits -= stock.OwnedUnits; } user.AvailableMoney += stock.OwnedUnits * price; await _context.SaveChangesAsync(); return(true); }
public async Task <IActionResult> SellStock(UserStocks stock) { var id = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value); stock.UserId = id; FpResponse unitsPrice = await Extensions.GetUnitsValue(); decimal unitPrice = Extensions.RoundDown(unitsPrice.items.Select(i => i.Price).FirstOrDefault(), 2); var fpStockData = unitsPrice.items.FirstOrDefault(x => x.Code == stock.CompanyCode); if (fpStockData == null) { return(BadRequest("There is no company with this name")); } else if (stock.OwnedUnits % fpStockData.Unit != 0) { return(BadRequest("Wrong quantity of units")); } var sellStock = await _repo.SellStock(stock, unitPrice); if (sellStock == false) { return(BadRequest("Wrong data!")); } return(Ok(true)); }
// Get User Portolio Information from the database public void UpdateUserPortfolio(String user, String symbol, String quantity) { if (dbContext.UserStock.Where(c => c.user.Equals(user) && c.symbol.Equals(symbol)).Count() == 0) { UserStocks stock = new UserStocks(); stock.user = user; stock.symbol = symbol; stock.quantity = quantity; dbContext.UserStock.Add(stock); } else { IQueryable <UserStocks> userStockList = dbContext.UserStock.Where(c => c.user.Equals(user) && c.symbol.Equals(symbol)); String oldQuantity = userStockList.First().quantity; userStockList.First().quantity = (int.Parse(oldQuantity) + int.Parse(quantity)) + ""; } dbContext.SaveChanges(); }
public async Task <bool> BuyStock(UserStocks stock, decimal price) { var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == stock.UserId); var stockExchnage = await _context.Users.FirstOrDefaultAsync(u => u.Username.ToLower() == Extensions.STOCK_EXCHANGE); var stockExchnageStocks = await _context.UserStocks.FirstOrDefaultAsync(us => us.UserId == stockExchnage.Id && us.CompanyCode == stock.CompanyCode); if (stockExchnageStocks.OwnedUnits < stock.OwnedUnits) { throw new Exception("Stock exchnage have too few units"); } else { stockExchnageStocks.OwnedUnits -= stock.OwnedUnits; } if (stock.OwnedUnits * price > user.AvailableMoney) { throw new Exception("You have too few money"); } user.AvailableMoney -= stock.OwnedUnits * price; UserStocks checkingStock = await _context.UserStocks.Where(us => us.UserId == stock.UserId && us.CompanyCode == stock.CompanyCode).FirstOrDefaultAsync(); if (checkingStock == null) { await _context.UserStocks.AddAsync(stock); } else { checkingStock.OwnedUnits += stock.OwnedUnits; } await _context.SaveChangesAsync(); return(true); }
/// <summary> /// ������֤���Ʊ /// </summary> /// <param name="SZRate"></param> /// <param name="userFund"></param> /// <param name="userOrder"></param> /// <param name="userStock"></param> /// <param name="dBoughtAmount"></param> /// <returns></returns> private bool BuySZ(ref SjshqDBFRecord SZRate, ref UserFund userFund, ref UserOrders userOrder, ref UserStocks userStock, out double dBoughtAmount) { try { dBoughtAmount = 0; if (userOrder.UserID != userFund.UserID || userStock.UserID != userFund.UserID) return false; else if (!userOrder.Side || userOrder.OrdStatus != OrderStatus.Waiting || userFund.UserID != userOrder.UserID) return false; else if (userOrder.OrderVolume < 0) return false; else if (SZRate.SellingVal1 < 0.001 || SZRate.LatestPrice < 0.001) return false; UserFund tmpFund = userFund; UserOrders tmpOrder = userOrder; UserStocks tmpStock = userStock; dBoughtAmount = Common.ConvertPrice((tmpOrder.OrderVolume * SZRate.SellingVal1) * (1 + defaultBuyTax)); if (Common.ComparePrice(userFund.Cash, dBoughtAmount) >= 0) { tmpFund.UsableCash += Common.ConvertPrice((tmpOrder.OrderVolume * tmpOrder.OrderPrice) * (1 + defaultBuyTax)); tmpFund.UsableCash -= Common.ConvertPrice(dBoughtAmount); Synchronizer.FundHistory fundHistory = new Synchronizer.FundHistory(); fundHistory.Initialize(); fundHistory.UserID = userFund.UserID; fundHistory.OrderID = userOrder.OrderID; fundHistory.OriginalCash = Common.ConvertPrice(userFund.Cash); tmpFund.Cash -= Common.ConvertPrice(dBoughtAmount); fundHistory.ChangedCash = Common.ConvertPrice(tmpFund.Cash - fundHistory.OriginalCash); fundHistory.Curr = tmpOrder.Curr; Common.DBSync.FundChanged(fundHistory, userFund.UserID); if (tmpStock.Volume + tmpOrder.OrderVolume > 0) tmpStock.AveragePrice = Common.ConvertPrice( ((tmpStock.AveragePrice * tmpStock.Volume) + (SZRate.SellingVal1 * tmpOrder.OrderVolume)) / (tmpStock.Volume + tmpOrder.OrderVolume) * (1 + defaultBuyTax)); else tmpStock.AveragePrice = 0; tmpStock.Volume += tmpOrder.OrderVolume; tmpStock.Curr = tmpOrder.Curr; if (GetStockType(tmpOrder.StockCode, StockMarket.Shenzhen) == StockType.SZ_Warrant) tmpStock.Sellable = true; else tmpStock.Sellable = false; if (tmpFund.UsableCash < 0) tmpFund.UsableCash = 0; } else { tmpOrder.UpdatedDate = DateTime.Now; tmpOrder.OrdStatus = OrderStatus.Failure; Common.DBSync.RecordError(tmpOrder, "(SZ)���㣺Currency-" + userFund.Curr.ToString().Trim() + "/Cash-" + userFund.Cash.ToString("f3").Trim() + "/Cost-" + dBoughtAmount.ToString("f3").Trim()); } if (tmpOrder.OrdStatus != OrderStatus.Failure) { tmpOrder.TradePrice = Common.ConvertPrice(SZRate.SellingVal1); if (tmpOrder.OrdType == OrderType.ImmediateOrder) tmpOrder.OrderPrice = 0; tmpOrder.UpdatedDate = DateTime.Now; tmpOrder.OrdStatus = OrderStatus.Finished; userFund = tmpFund; userStock = tmpStock; } userOrder = tmpOrder; if (userOrder.OrdStatus == OrderStatus.Finished) return true; else return false; } catch { dBoughtAmount = 0; return false; } }
/// <summary> /// �����û���Ʊ /// </summary> /// <param name="listUserStocks"></param> /// <param name="userStock"></param> /// <returns></returns> private bool UpdateUserStock(ref List<UserStocks> listUserStocks, UserStocks userStock) { try { if (listUserStocks == null) return false; bool bExist = false; for (int i = 0; i < listUserStocks.Count; i++) { if (listUserStocks[i].UserID == userStock.UserID && string.Compare(userStock.StockCode.Trim() , listUserStocks[i].StockCode.Trim()) == 0 && userStock.Market == listUserStocks[i].Market && userStock.Sellable == listUserStocks[i].Sellable) { bExist = true; if (userStock.Volume > 0) listUserStocks[i] = userStock; else listUserStocks.RemoveAt(i--); break; } } if (!bExist && userStock.Volume > 0) listUserStocks.Add(userStock); return true; } catch { return false; } }
/// <summary> /// ������ת���� /// </summary> private void Trading() { try { ushort uFlag = 0; List<int> listUserOrdersKeys = new List<int>(); //�ʽ𣬶������ֹɽԲ�Ϊ��ʱ��ϵͳ������� while (bTrading && mapUserFund != null && mapUserOrders != null && mapUserStocks != null) { try { if (!Management.Work || Common.IsWeekend) { Thread.Sleep(30000); continue; } else { //���ڽӿڿ���ʱ�� if (Common.IsInInterfaceQuotationTime) { //ͳ�ƻ����еļ�ʱ�������۶���������������ί���� int ICount = 0, LCount = 0, CCount = 0; if (++uFlag % 500 == 0 && GetTotalWaitingOrdersCount(out ICount, out LCount, out CCount)) { Common.Log("--- Orders in Buffer (Total: " + (ICount + LCount + CCount) + ") ---" + Environment.NewLine + "[ImmediateOrder=" + ICount + "] [LimitedOrder=" + LCount + "] [CancelOrder=" + CCount + "]"); uFlag = 0; } } //���ڽ���ʱ�Σ�����ʱ��ֱ�Ӻ��� if (DateTime.Now.TimeOfDay < Common.BeginAMTS || DateTime.Now.TimeOfDay > Common.EndPMTS.Add(new TimeSpan(0, 5, 0))) { Thread.Sleep(30000); continue; } } //���������Ϣ if (Common.stkQuotation != null && mapUserOrders.Count > 0 && Common.stkQuotation.GetSnapShot()) { int nOrderID = -1; listUserOrdersKeys.Clear(); Show2003DBFRecord SHRate = new Show2003DBFRecord(); SHRate.Clear(); SjshqDBFRecord SZRate = new SjshqDBFRecord(); SZRate.Clear(); foreach (object objKey in mapUserOrders.Keys) { if (objKey == null) continue; nOrderID = Convert.ToInt32(objKey); if (nOrderID < 0 || !mapUserOrders.ContainsKey(nOrderID)) continue; listUserOrdersKeys.Add(nOrderID);//���붩��ID������������� } //�Լ��뵽����������еĶ������д��� foreach (int OrderKey in listUserOrdersKeys) { try { if (!mapUserOrders.ContainsKey(OrderKey)) continue; UserOrders userOrder = mapUserOrders[OrderKey]; if (!mapUserFund.ContainsKey(userOrder.UserID)) continue; Dictionary<byte, UserFund> mapCurrFund = mapUserFund[userOrder.UserID]; if (!mapCurrFund.ContainsKey((byte)userOrder.Curr)) continue; UserFund userFund = mapCurrFund[(byte)userOrder.Curr]; if (userOrder.StockCode == null || userOrder.StockCode.Trim().Length <= 0 || userOrder.Market == StockMarket.Unknown || userOrder.OrdStatus == OrderStatus.Unknown) { mapUserOrders.Remove(OrderKey); } else if (userOrder.OrdStatus != OrderStatus.Waiting && userOrder.OrdStatus != OrderStatus.Cancelling) { continue; } else { if (userOrder.ExpiredDate < DateTime.Now && (userOrder.OrdStatus == OrderStatus.Waiting || userOrder.OrdStatus == OrderStatus.Cancelling)) { #region �ö����ѹ��� userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; Common.DBSync.RecordError(userOrder, "���ڶ�����" + userOrder.ExpiredDate.ToString("yyyy-MM-dd HH:mm:ss").Trim()); if (userOrder.OrdType == TradingSystem.OrderType.LimitedOrder) { userFund.UsableCash += Common.ConvertPrice((userOrder.OrderPrice * userOrder.OrderVolume) * (1 + Common.stkTrading.defaultBuyTax)); if (!Common.DBSync.FundUpdate(userFund, userOrder.UserID)) continue; SetUserFund(userFund.UserID, userFund); } if (Common.DBSync.OrderChanged(mapCurrFund[(byte)userFund.Curr], userOrder, new UserStocks())) { lock (mapUserFund) mapUserFund[userOrder.UserID] = mapCurrFund; lock (mapUserOrders) mapUserOrders[OrderKey] = userOrder; Common.Debug("Order Status Changed [" + userOrder.OrdStatus.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } #endregion } else if (userOrder.OrdStatus == OrderStatus.Cancelling) { #region ȡ������ if (userOrder.OrdType == OrderType.LimitedOrder) { userOrder.OrdStatus = OrderStatus.Cancelled; userOrder.UpdatedDate = DateTime.Now; if (Common.DBSync.OrderChanged(mapCurrFund[(byte)userFund.Curr], userOrder, new UserStocks())) { mapUserOrders[userOrder.OrderID] = userOrder; if (userOrder.Side) { UserFund usableFund = mapCurrFund[(byte)userFund.Curr]; usableFund.UsableCash += Common.ConvertPrice((userOrder.OrderVolume * userOrder.OrderPrice) * (1 + defaultBuyTax)); SetUserFund(usableFund.UserID, usableFund); Common.DBSync.FundUpdate(usableFund, userOrder.UserID); } Common.Debug("Order Status Changed [" + userOrder.OrdStatus.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } else { userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; lock (mapUserOrders) mapUserOrders[userOrder.OrderID] = userOrder; Common.DBSync.RecordError(userOrder, "����ʧ�ܣ��û�ID-" + userOrder.UserID + "������ID-" + userOrder.OrderID); } } else { userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; lock (mapUserOrders) mapUserOrders[userOrder.OrderID] = userOrder; Common.DBSync.RecordError(userOrder, "��Ч�������û�ID-" + userOrder.UserID + "������ID-" + userOrder.OrderID); } #endregion } else if (userOrder.OrdStatus == OrderStatus.Waiting && !Common.stkQuotation.GetStkRate(userOrder.StockCode, userOrder.Market, out SHRate, out SZRate)) { #region ��������� userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; Common.DBSync.RecordError(userOrder, "��������飺" + userOrder.StockCode.Trim() + "-" + userOrder.Market.ToString().Trim()); if (userOrder.OrdType == TradingSystem.OrderType.LimitedOrder) { userFund.UsableCash += Common.ConvertPrice((userOrder.OrderPrice * userOrder.OrderVolume) * (1 + Common.stkTrading.defaultBuyTax)); SetUserFund(userFund.UserID, userFund); if (!Common.DBSync.FundUpdate(userFund, userOrder.UserID)) continue; } if (Common.DBSync.OrderChanged(mapCurrFund[(byte)userFund.Curr], userOrder, new UserStocks())) { lock (mapUserFund) mapUserFund[userOrder.UserID] = mapCurrFund; lock (mapUserOrders) mapUserOrders[OrderKey] = userOrder; Common.Debug("Order Status Changed [" + userOrder.OrdStatus.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } #endregion } else if (userOrder.OrdStatus == OrderStatus.Waiting && (userOrder.Market == StockMarket.Shanghai && (SHRate.LatestPrice < 0.001 || SHRate.OpenPrice < 0.001)) || (userOrder.Market == StockMarket.Shenzhen && (SZRate.LatestPrice < 0.001 || SZRate.OpenPrice < 0.001))) { #region �ù�Ʊͣ�� userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; Common.DBSync.RecordError(userOrder, "ͣ�ƹ�Ʊ��" + userOrder.StockCode.Trim() + "-" + userOrder.Market.ToString().Trim()); if (userOrder.OrdType == TradingSystem.OrderType.LimitedOrder) { userFund.UsableCash += Common.ConvertPrice((userOrder.OrderPrice * userOrder.OrderVolume) * (1 + Common.stkTrading.defaultBuyTax)); SetUserFund(userFund.UserID, userFund); if (!Common.DBSync.FundUpdate(userFund, userOrder.UserID)) continue; } if (Common.DBSync.OrderChanged(mapCurrFund[(byte)userFund.Curr], userOrder, new UserStocks())) { lock (mapUserFund) mapUserFund[userOrder.UserID] = mapCurrFund; lock (mapUserOrders) mapUserOrders[OrderKey] = userOrder; Common.Debug("Order Status Changed [" + userOrder.OrdStatus.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } #endregion } else { if (userOrder.OrdStatus == OrderStatus.Waiting) { double dBargainAmount = 0; List<UserStocks> listUserStocks = new List<UserStocks>(); if (mapUserStocks.ContainsKey(userOrder.UserID)) listUserStocks = mapUserStocks[userOrder.UserID]; else mapUserStocks[userOrder.UserID] = new List<UserStocks>(); UserStocks userStock = new UserStocks(); userStock.Initialize(); bool bExist = false; for (int i = 0; i < listUserStocks.Count; i++) { if (listUserStocks[i].UserID == userOrder.UserID && string.Compare(userOrder.StockCode.Trim() , listUserStocks[i].StockCode.Trim()) == 0 && userOrder.Market == listUserStocks[i].Market && ((!userOrder.Side && listUserStocks[i].Sellable) || (userOrder.Side && !listUserStocks[i].Sellable))) { bExist = true; userStock = listUserStocks[i]; break; } } if (!bExist) { userStock.UserID = userOrder.UserID; userStock.StockCode = userOrder.StockCode.Trim(); userStock.Market = userOrder.Market; userStock.Sellable = false; } switch (userOrder.OrdType) { #region �м۽��� case OrderType.ImmediateOrder: { Common.Debug("--- [ImmediateOrder] Received. ---"); if (userOrder.Side) { // ���� if (userOrder.Market == StockMarket.Shanghai) { if (SHRate.SellingVal1 < 0.001 || Common.ComparePrice(SHRate.HighestPrice, SHRate.LowestPrice) <= 0) { userOrder.OrderPrice = SHRate.SellingVal1; if (Common.ComparePrice(userFund.UsableCash, (SHRate.SellingVal1 * userOrder.OrderVolume) * (1 + defaultBuyTax)) < 0) { userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; } else { userOrder.OrdType = OrderType.LimitedOrder; Common.DBSync.OrderChanged(userFund, userOrder, new UserStocks()); userFund.UsableCash -= Common.ConvertPrice((userOrder.OrderPrice * userOrder.OrderVolume) * (1 + defaultBuyTax) + 0.0099); Common.DBSync.FundUpdate(userFund, userOrder.UserID); mapCurrFund[(byte)userFund.Curr] = userFund; mapUserFund[userOrder.UserID] = mapCurrFund; mapUserOrders[OrderKey] = userOrder; Common.Debug("Order Type Changed [" + userOrder.OrdType.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } } else { userOrder.OrderPrice = SHRate.SellingVal1; if (Common.ComparePrice(userFund.UsableCash, (SHRate.SellingVal1 * userOrder.OrderVolume) * (1 + defaultBuyTax)) < 0) { userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; } else if (BuySH(ref SHRate, ref userFund, ref userOrder, ref userStock, out dBargainAmount)) { UpdateUserStock(ref listUserStocks, userStock); userFund.UsableCash -= Common.ConvertPrice((SHRate.SellingVal1 * userOrder.OrderVolume) * (1 + defaultBuyTax) + 0.0099); Common.DBSync.FundUpdate(userFund, userOrder.UserID); } } } else if (userOrder.Market == StockMarket.Shenzhen) { if (SZRate.SellingVal1 < 0.001 || Common.ComparePrice(SZRate.HighestPrice, SZRate.LowestPrice) <= 0) { userOrder.OrderPrice = SZRate.SellingVal1; if (Common.ComparePrice(userFund.UsableCash, (SZRate.SellingVal1 * userOrder.OrderVolume) * (1 + defaultBuyTax)) < 0) { userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; } else { userOrder.OrdType = OrderType.LimitedOrder; Common.DBSync.OrderChanged(userFund, userOrder, new UserStocks()); userFund.UsableCash -= Common.ConvertPrice((userOrder.OrderPrice * userOrder.OrderVolume) * (1 + defaultBuyTax) + 0.0099); Common.DBSync.FundUpdate(userFund, userOrder.UserID); mapCurrFund[(byte)userFund.Curr] = userFund; mapUserFund[userOrder.UserID] = mapCurrFund; mapUserOrders[OrderKey] = userOrder; Common.Debug("Order Type Changed [" + userOrder.OrdType.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } } else { userOrder.OrderPrice = SHRate.SellingVal1; if (Common.ComparePrice(userFund.UsableCash, (SHRate.SellingVal1 * userOrder.OrderVolume) * (1 + defaultBuyTax)) < 0) { userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; } else if (BuySZ(ref SZRate, ref userFund, ref userOrder, ref userStock, out dBargainAmount)) { UpdateUserStock(ref listUserStocks, userStock); userFund.UsableCash -= Common.ConvertPrice((SZRate.SellingVal1 * userOrder.OrderVolume) * (1 + defaultBuyTax) + 0.0099); Common.DBSync.FundUpdate(userFund, userOrder.UserID); } } } } else { // ��� if (userOrder.Market == StockMarket.Shanghai) { if (SHRate.BuyingVal1 < 0.001 || Common.ComparePrice(SHRate.HighestPrice, SHRate.LowestPrice) <= 0) { userOrder.OrderPrice = SHRate.BuyingVal1; userOrder.OrdType = OrderType.LimitedOrder; Common.DBSync.OrderChanged(userFund, userOrder, new UserStocks()); mapUserOrders[OrderKey] = userOrder; Common.Debug("Order Type Changed [" + userOrder.OrdType.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } else if (SellSH(ref SHRate, ref userFund, ref userOrder, ref userStock, out dBargainAmount)) { userOrder.OrderPrice = SHRate.BuyingVal1; UpdateUserStock(ref listUserStocks, userStock); Common.DBSync.FundUpdate(userFund, userOrder.UserID); } } else if (userOrder.Market == StockMarket.Shenzhen) { if (SZRate.BuyingVal1 < 0.001 || Common.ComparePrice(SZRate.HighestPrice, SZRate.LowestPrice) <= 0) { userOrder.OrderPrice = SZRate.BuyingVal1; userOrder.OrdType = OrderType.LimitedOrder; Common.DBSync.OrderChanged(userFund, userOrder, new UserStocks()); mapUserOrders[OrderKey] = userOrder; Common.Debug("Order Type Changed [" + userOrder.OrdType.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } else if (SellSZ(ref SZRate, ref userFund, ref userOrder, ref userStock, out dBargainAmount)) { userOrder.OrderPrice = SZRate.BuyingVal1; UpdateUserStock(ref listUserStocks, userStock); Common.DBSync.FundUpdate(userFund, userOrder.UserID); } } } } break; #endregion #region �۽��� case OrderType.LimitedOrder: { if (userOrder.Side) { // ���� if (userOrder.Market == StockMarket.Shanghai && SHRate.SellingVal1 >= 0.001 && Common.ComparePrice(SHRate.HighestPrice, SHRate.LowestPrice) > 0 && Common.ComparePrice(SHRate.SellingVal1, userOrder.OrderPrice) <= 0) { if (IsOrderValid(ref SHRate, ref userFund, ref userOrder) && BuySH(ref SHRate, ref userFund, ref userOrder, ref userStock, out dBargainAmount)) UpdateUserStock(ref listUserStocks, userStock); Common.DBSync.FundUpdate(userFund, userOrder.UserID); } else if (userOrder.Market == StockMarket.Shenzhen && SZRate.SellingVal1 >= 0.001 && Common.ComparePrice(SZRate.HighestPrice, SZRate.LowestPrice) > 0 && Common.ComparePrice(SZRate.SellingVal1, userOrder.OrderPrice) <= 0) { if (IsOrderValid(ref SZRate, ref userFund, ref userOrder) && BuySZ(ref SZRate, ref userFund, ref userOrder, ref userStock, out dBargainAmount)) UpdateUserStock(ref listUserStocks, userStock); Common.DBSync.FundUpdate(userFund, userOrder.UserID); } } else { // ��� if (userOrder.Market == StockMarket.Shanghai && SHRate.BuyingVal1 >= 0.001 && Common.ComparePrice(SHRate.HighestPrice, SHRate.LowestPrice) > 0 && Common.ComparePrice(SHRate.BuyingVal1, userOrder.OrderPrice) >= 0) { if (IsOrderValid(ref SHRate, ref userFund, ref userOrder) && SellSH(ref SHRate, ref userFund, ref userOrder, ref userStock, out dBargainAmount)) UpdateUserStock(ref listUserStocks, userStock); Common.DBSync.FundUpdate(userFund, userOrder.UserID); } else if (userOrder.Market == StockMarket.Shenzhen && SZRate.BuyingVal1 >= 0.001 && Common.ComparePrice(SZRate.HighestPrice, SZRate.LowestPrice) > 0 && Common.ComparePrice(SZRate.BuyingVal1, userOrder.OrderPrice) >= 0) { if (IsOrderValid(ref SZRate, ref userFund, ref userOrder) && SellSZ(ref SZRate, ref userFund, ref userOrder, ref userStock, out dBargainAmount)) UpdateUserStock(ref listUserStocks, userStock); Common.DBSync.FundUpdate(userFund, userOrder.UserID); } } } break; #endregion default: { userOrder.OrdStatus = OrderStatus.Failure; userOrder.UpdatedDate = DateTime.Now; Common.DBSync.RecordError(userOrder, "δ֪�Ķ������ͣ�" + userOrder.OrdType.ToString().Trim()); lock (mapUserOrders) mapUserOrders[OrderKey] = userOrder; } break; } if (userOrder.OrdStatus != OrderStatus.Waiting && Common.DBSync.OrderChanged(userFund, userOrder, userStock)) { SetUserFund(userFund.UserID, userFund); lock (mapUserOrders) mapUserOrders[OrderKey] = userOrder; lock (mapUserStocks) mapUserStocks[userOrder.UserID] = listUserStocks; Common.Debug("Order Status Changed [" + userOrder.OrdStatus.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } } else Common.Log("Illegal Order Status [" + userOrder.OrdStatus.ToString() + "] [UserID=" + userOrder.UserID + "] [OrderID=" + userOrder.OrderID + "]."); } } } catch (Exception err) { Common.Log(err); } } } lock (listNewUserFund) { if (listNewUserFund.Count > 0) { for (int i = 0; i < listNewUserFund.Count; i++) { if (!mapUserFund.ContainsKey(listNewUserFund[i].UserID)) { mapUserFund[listNewUserFund[i].UserID] = new Dictionary<byte, UserFund>(); Dictionary<byte, UserFund> mapCurrFund = mapUserFund[listNewUserFund[i].UserID]; mapCurrFund[(byte)listNewUserFund[i].Curr] = listNewUserFund[i]; mapUserFund[listNewUserFund[i].UserID] = mapCurrFund; } else if (!mapUserFund[listNewUserFund[i].UserID].ContainsKey((byte)listNewUserFund[i].Curr)) { Dictionary<byte, UserFund> mapCurrFund = mapUserFund[listNewUserFund[i].UserID]; mapCurrFund[(byte)listNewUserFund[i].Curr] = listNewUserFund[i]; mapUserFund[listNewUserFund[i].UserID] = mapCurrFund; } } listNewUserFund.Clear(); } } lock (listNewUserOrders) { if (listNewUserOrders.Count > 0) { for (int i = 0; i < listNewUserOrders.Count; i++) { if (!mapUserOrders.ContainsKey(listNewUserOrders[i].OrderID)) mapUserOrders[listNewUserOrders[i].OrderID] = listNewUserOrders[i]; } listNewUserOrders.Clear(); } } } catch (Exception err) { Common.Log(err); } Thread.Sleep(1000); } } catch (Exception err) { Common.Log(err); if (Common.DBSync != null) Common.DBSync.Uninitialize(mapUserFund, mapUserOrders, mapUserStocks); Common.Log("Error: The Trading Thread Has Crashed !"); } }
/// <summary> /// �����֤���Ʊ /// </summary> /// <param name="SZRate"></param> /// <param name="userFund"></param> /// <param name="userOrder"></param> /// <param name="userStock"></param> /// <param name="dSoldAmount"></param> /// <returns></returns> private bool SellSZ(ref SjshqDBFRecord SZRate, ref UserFund userFund, ref UserOrders userOrder, ref UserStocks userStock, out double dSoldAmount) { try { dSoldAmount = 0; if (userOrder.UserID != userFund.UserID || userStock.UserID != userFund.UserID) return false; else if (userOrder.Side || userOrder.OrdStatus != OrderStatus.Waiting || userFund.UserID != userOrder.UserID) return false; else if (userOrder.OrderVolume < 0) return false; else if (SZRate.BuyingVal1 < 0.001 || SZRate.LatestPrice < 0.001) return false; UserFund tmpFund = userFund; UserOrders tmpOrder = userOrder; UserStocks tmpStock = userStock; dSoldAmount = Common.ConvertPrice((tmpOrder.OrderVolume * SZRate.BuyingVal1) * (1 - defaultSellTax)); if (tmpStock.Volume >= tmpOrder.OrderVolume) { tmpStock.Volume -= tmpOrder.OrderVolume; Synchronizer.FundHistory fundHistory = new Synchronizer.FundHistory(); fundHistory.Initialize(); fundHistory.UserID = userFund.UserID; fundHistory.OrderID = userOrder.OrderID; fundHistory.OriginalCash = Common.ConvertPrice(userFund.Cash); tmpFund.Cash += Common.ConvertPrice(dSoldAmount); fundHistory.ChangedCash = Common.ConvertPrice(tmpFund.Cash - fundHistory.OriginalCash); fundHistory.Curr = tmpOrder.Curr; Common.DBSync.FundChanged(fundHistory, userFund.UserID); tmpFund.UsableCash += Common.ConvertPrice(dSoldAmount); if (tmpStock.Volume > 0) tmpStock.AveragePrice = Common.ConvertPrice( ((tmpStock.AveragePrice * tmpStock.Volume) + (SZRate.BuyingVal1 * tmpOrder.OrderVolume)) / (tmpStock.Volume + tmpOrder.OrderVolume) * (1 + defaultSellTax)); else tmpStock.AveragePrice = 0; if (tmpFund.Cash < 0) tmpFund.Cash = 0; if (tmpFund.UsableCash < 0) tmpFund.UsableCash = 0; } else { tmpOrder.UpdatedDate = DateTime.Now; tmpOrder.OrdStatus = OrderStatus.Failure; Common.DBSync.RecordError(tmpOrder, "(SZ)��ɲ��㣺Volume" + tmpStock.Volume.ToString().Trim() + "/Cost-" + tmpOrder.OrderVolume.ToString().Trim()); } if (tmpOrder.OrdStatus != OrderStatus.Failure) { tmpOrder.TradePrice = Common.ConvertPrice(SZRate.BuyingVal1); if (tmpOrder.OrdType == OrderType.ImmediateOrder) tmpOrder.OrderPrice = 0; tmpOrder.UpdatedDate = DateTime.Now; tmpOrder.OrdStatus = OrderStatus.Finished; userFund = tmpFund; userStock = tmpStock; } userOrder = tmpOrder; if (userOrder.OrdStatus == OrderStatus.Finished) return true; else return false; } catch { dSoldAmount = 0; return false; } }
public StockSellStatus SellStock(string userId, SellStockViewModel sellStockModel) { // check if user change the form data, provided stock value has to exists in database StockValue sellingStockValue = GetStockForCodeAndValue( sellStockModel.Code, sellStockModel.Unit, sellStockModel.Price); if (sellingStockValue == null) { return(StockSellStatus.Unknown); } decimal totalCost = sellStockModel.AmountToSell / sellingStockValue.Unit * sellingStockValue.Price; // case 1: User does not have enough stock User seller = _db.UserApp.Where(x => x.Id.Equals(userId)).FirstOrDefault(); UserStocks stockOwnedBySeller = seller.Stocks .Where(x => x.StockID == sellingStockValue.StockID) .FirstOrDefault(); if (stockOwnedBySeller == null || stockOwnedBySeller.Amount < sellStockModel.AmountToSell) { return(StockSellStatus.UserHasNotEnoughStocks); } // case 2: Stock value data have changed - there was an update StockDetails latestStockDetails = GetLatestStockDetails(sellStockModel.Code); bool isSellerSellingStockByLatestPrice = AreDatesTheSameComparisonLikeHuman( latestStockDetails.PublicationDate, sellingStockValue.PublicationDate); if (isSellerSellingStockByLatestPrice == false) { return(StockSellStatus.StockValueDataHaveChanged); } using (var dbContextTransaction = _db.Database.BeginTransaction()) { try { // then 1: Add money to User wallet seller.Money += totalCost; // then 2: Subtract specified amount of stock from UserStocks stockOwnedBySeller.Amount -= sellStockModel.AmountToSell; if (stockOwnedBySeller.Amount == 0) { _db.UserStocks.Remove(stockOwnedBySeller); } //then 3: Increase available stock amount _db.Stock.Attach(sellingStockValue.Stock); _db.Entry(sellingStockValue.Stock).Reload(); sellingStockValue.Stock.AvailableAmount += sellStockModel.AmountToSell; _db.Entry(sellingStockValue.Stock).State = System.Data.Entity.EntityState.Modified; // save and commit _db.SaveChanges(); dbContextTransaction.Commit(); return(StockSellStatus.Success); // everything went well, so finally success } catch (Exception e) { _logger.Error("Transaction error during selling stock. Error " + e.Message); _logger.Error("Rollback..."); dbContextTransaction.Rollback(); } } return(StockSellStatus.Unknown); }
public StockBuyStatus BuyStock(string userId, BuyStockViewModel buyStockModel) { // check if user change the form data, provided stock value has to exists in database StockValue purchasingStockValue = GetStockForCodeAndValue(buyStockModel.Code, buyStockModel.Unit, buyStockModel.Price); if (purchasingStockValue == null) { return(StockBuyStatus.Unknown); } decimal totalCost = buyStockModel.AmountToBuy / purchasingStockValue.Unit * purchasingStockValue.Price; // case 1: User does not have enough money User buyer = _db.UserApp.Where(x => x.Id.Equals(userId) && x.Money >= totalCost) .FirstOrDefault(); if (buyer == null) { return(StockBuyStatus.UserHasNotEnoughMoney); } // case 2: Stock Exchange does not have enough stock if (purchasingStockValue.Stock.AvailableAmount < buyStockModel.AmountToBuy) { return(StockBuyStatus.AmountNotAvailable); } // case 3: Stock value data have changed - there was an update StockDetails latestStockDetails = GetLatestStockDetails(buyStockModel.Code); bool isBuyerBuyingStockByLatestPrice = AreDatesTheSameComparisonLikeHuman( latestStockDetails.PublicationDate, purchasingStockValue.PublicationDate); if (isBuyerBuyingStockByLatestPrice == false) { return(StockBuyStatus.StockValueDataHaveChanged); } using (var dbContextTransaction = _db.Database.BeginTransaction()) { try { // then 1: Subtract money from User wallet buyer.Money -= totalCost; // then 2: Add specified amount of stock to UserStocks UserStocks stockOwnedByBuyer = buyer.Stocks.FirstOrDefault( x => x.StockID == purchasingStockValue.StockID); if (stockOwnedByBuyer != null) { stockOwnedByBuyer.Amount += buyStockModel.AmountToBuy; _db.Entry(stockOwnedByBuyer).State = System.Data.Entity.EntityState.Modified; } else { stockOwnedByBuyer = new UserStocks { UserID = userId, StockID = purchasingStockValue.StockID, Amount = buyStockModel.AmountToBuy }; _db.UserStocks.Add(stockOwnedByBuyer); } // then 3: Decrease available stock amount _db.Stock.Attach(purchasingStockValue.Stock); _db.Entry(purchasingStockValue.Stock).Reload(); if (purchasingStockValue.Stock.AvailableAmount < buyStockModel.AmountToBuy) { _logger.Info("Rollback"); dbContextTransaction.Rollback(); return(StockBuyStatus.AmountNotAvailable); } purchasingStockValue.Stock.AvailableAmount -= buyStockModel.AmountToBuy; _db.Entry(purchasingStockValue.Stock).State = System.Data.Entity.EntityState.Modified; // save and commit _db.SaveChanges(); dbContextTransaction.Commit(); return(StockBuyStatus.Success); // everything went well, so finally success } catch (Exception e) { _logger.Error("Transaction error during buying stock. Error:" + e.Message); _logger.Error("Rollback..."); dbContextTransaction.Rollback(); } } return(StockBuyStatus.Unknown); }