public Position DoClosePosition(int userId, int posId, int secId, decimal closePrice) { Position position = null; using ( var scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable })) { using (var dbIsolated = YJYEntities.Create()) { position = dbIsolated.Positions.FirstOrDefault(o => o.Id == posId && o.UserId == userId && o.SecurityId == secId); var user = dbIsolated.Users.FirstOrDefault(o => o.Id == userId); if (user == null || position == null) { throw new ObjectNotFoundException(); } //position's balance, not user's current active balance var balance = dbIsolated.Balances.FirstOrDefault(o => o.Id == position.BalanceId && o.UserId == user.Id); if (position.ClosedAt == null) { var pl = Trades.CalculatePL(position, closePrice); position.ClosedAt = DateTime.UtcNow; position.ClosePrice = closePrice; position.PL = pl; var pValue = position.Invest + pl; if (pValue > 0) { balance.Amount = balance.Amount + pValue; } //add a new transfer dbIsolated.Transfers.Add(new Transfer() { Amount = pValue, BalanceAfter = balance.Amount, Time = DateTime.UtcNow, Type = TransferType.Close.ToString(), UserId = user.Id, PositionId = position.Id, BalanceId = balance.Id, }); dbIsolated.SaveChanges(); } } scope.Complete(); } return(position); }
public PositionDTO SetStopTake(StopTakeFormDTO form) { var position = db.Positions.FirstOrDefault(o => o.Id == form.posId && o.UserId == UserId); if (position == null) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "no such position")); } if (position.ClosedAt != null) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "position closed")); } if (position.FollowPosId != null || position.FollowUserId != null) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "cannot set stop/take for followed position")); } //var quote = WebCache.Instance.Quotes.FirstOrDefault(o => o.Id == position.SecurityId); //var lastPrice = Quotes.GetLastPrice(quote); if (form.stopPx != null) { if (Trades.CalculatePL(position, form.stopPx.Value, false) + position.Invest <= 0) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "stop cannot be <= 0%")); } //if(position.Side.Value && form.stopPx>=lastPrice || !position.Side.Value && form.stopPx<=lastPrice) // throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, // "invalid stopPx against current price")); } if (position.StopPx != form.stopPx) { position.StopPx = form.stopPx; position.StopSetAt = DateTime.UtcNow; } if (position.TakePx != form.takePx) { position.TakePx = form.takePx; position.TakeSetAt = DateTime.UtcNow; } db.SaveChanges(); return(Mapper.Map <PositionDTO>(position)); }
public List <PositionDTO> GetOpenPositions(int pageNum = 1, int pageSize = YJYGlobal.DEFAULT_PAGE_SIZE) { var me = GetUser(); var positions = db.Positions.Where(o => o.UserId == UserId && o.ClosedAt == null && o.BalanceId == me.ActiveBalanceId) .OrderByDescending(o => o.CreateTime) .Skip((pageNum - 1) * pageSize).Take(pageSize) .ToList(); var followUserIds = positions.Where(o => o.FollowUserId.HasValue).Select(o => o.FollowUserId).ToList(); var users = db.Users.Where(o => followUserIds.Contains(o.Id)).ToList(); var cache = WebCache.Instance; var positionDtos = positions.Select(delegate(Position p) { var prodDef = cache.ProdDefs.FirstOrDefault(o => o.Id == Convert.ToInt32(p.SecurityId)); var quote = cache.Quotes.FirstOrDefault(o => o.Id == Convert.ToInt32(p.SecurityId)); var security = Mapper.Map <SecurityDetailDTO>(prodDef); if (quote != null) { security.last = Quotes.GetLastPrice(quote); //security.ask = quote.Ask; //security.bid = quote.Bid; } var posDTO = Mapper.Map <PositionDTO>(p); //security posDTO.security = security; //calculate UPL posDTO.upl = Trades.CalculatePL(p, quote); if (p.FollowUserId.HasValue) { var user = users.FirstOrDefault(o => o.Id == p.FollowUserId.Value); posDTO.followUser = new UserBaseDTO() { id = user.Id, nickname = user.Nickname, picUrl = user.PicUrl, }; } return(posDTO); }).Where(o => o != null).ToList(); return(positionDtos); }
public List <PositionBaseDTO> GetUserOpenPositions(int userId) { var tryGetAuthUser = TryGetAuthUser(); int balanceTypeId = 1; if (tryGetAuthUser != null) { balanceTypeId = db.Balances.FirstOrDefault(o => o.Id == tryGetAuthUser.ActiveBalanceId).TypeId; } var positions = db.Positions.Where(p => p.UserId == userId && p.ClosedAt == null && p.BalanceTypeId == balanceTypeId) .OrderByDescending(p => p.CreateTime) .Take(YJYGlobal.DEFAULT_PAGE_SIZE) .ToList(); var prods = WebCache.Instance.ProdDefs; var quotes = WebCache.Instance.Quotes; var result = new List <PositionBaseDTO>(); positions.ForEach(p => { var dto = new PositionBaseDTO(); dto.id = p.Id; var prodDef = prods.FirstOrDefault(pd => pd.Id == p.SecurityId); var quote = quotes.FirstOrDefault(o => o.Id == p.SecurityId); if (prodDef != null) { //dto.invest = p.Invest; dto.upl = Trades.CalculatePL(p, quote); dto.roi = dto.upl / p.Invest; dto.createAt = p.CreateTime; dto.isLong = p.Side; dto.security = new SecurityBaseDTO() { id = p.SecurityId.Value, name = Translator.GetProductNameByThreadCulture(prodDef.Name), symbol = prodDef.Symbol, }; } result.Add(dto); }); return(result); }
public BalanceDTO GetBalance() { var user = GetUser(); var balance = db.Balances.FirstOrDefault(o => o.Id == user.ActiveBalanceId); var openPositions = db.Positions.Where(o => o.UserId == UserId && o.ClosedAt == null && o.BalanceId == balance.Id).ToList(); var quotes = WebCache.Instance.Quotes; var sumOfPositionValue = openPositions.Sum( p => Trades.CalculatePL(p, quotes.FirstOrDefault(q => q.Id == p.SecurityId)) + p.Invest.Value); return(new BalanceDTO() { balance = balance.Amount.Value, total = balance.Amount.Value + sumOfPositionValue, balanceType = balance.TypeId == 1 ? "Demo" : "Live" }); }
public static List <Position> CheckAndCloseFollowPositions(int posIdToFollowClose) { List <Position> result = new List <Position>(); var db = YJYEntities.Create(); var basePosition = db.Positions.FirstOrDefault(o => o.Id == posIdToFollowClose); if (basePosition != null) { if (basePosition.ClosedAt != null && basePosition.ClosePrice != null) { var positions = db.Positions.Where(o => o.FollowPosId == basePosition.Id && o.ClosedAt == null).ToList(); foreach (var position in positions) { try { using ( var scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable })) { using (var dbIsolated = YJYEntities.Create()) { var p = dbIsolated.Positions.FirstOrDefault(o => o.Id == position.Id); var u = dbIsolated.Users.FirstOrDefault(o => o.Id == position.UserId); if (u == null || p == null) { throw new ObjectNotFoundException(); } //position's balance, not user's current active balance var b = dbIsolated.Balances.FirstOrDefault(o => o.Id == p.BalanceId && o.UserId == u.Id); if (p.ClosedAt == null) { var pl = Trades.CalculatePL(p, basePosition.ClosePrice.Value); p.ClosedAt = DateTime.UtcNow; p.ClosePrice = basePosition.ClosePrice.Value; p.PL = pl; p.CloseType = PositionCloseType.Follow.ToString(); var pValue = p.Invest + pl; if (pValue > 0) { b.Amount = b.Amount + pValue; } //add a new transfer dbIsolated.Transfers.Add(new Transfer() { Amount = pValue, BalanceAfter = b.Amount, Time = DateTime.UtcNow, Type = TransferType.Close.ToString(), UserId = u.Id, PositionId = p.Id, BalanceId = b.Id, }); dbIsolated.SaveChanges(); result.Add(p); } } scope.Complete(); } } catch (Exception e) { YJYGlobal.LogWarning("follow close error:"); YJYGlobal.LogExceptionAsWarning(e); } } } else { YJYGlobal.LogWarning("FOLLOW CLOSE fail: base position is not closed"); } } return(result); }
public static void Run() { YJYGlobal.LogLine("Starting..."); //var mapper = MapperConfig.GetAutoMapperConfiguration().CreateMapper(); _queueClient = new QueueClient(ServiceBusConnectionString, QueueName); while (true) { try { using (var redisClient = YJYGlobal.PooledRedisClientsManager.GetClient()) { var redisProdDefClient = redisClient.As <ProdDef>(); var redisQuoteClient = redisClient.As <Quote>(); //var redisTickClient = redisClient.As<Tick>(); using (var db = YJYEntities.Create()) { var openPositions = db.Positions.Where(o => o.ClosedAt == null).ToList(); var prodDefs = redisProdDefClient.GetAll(); var quotes = redisQuoteClient.GetAll(); var openPositionsNotSent = openPositions.Where(o => !_sentPosIds.ContainsKey(o.Id)).ToList(); if (new Random().NextDouble() > 0.9) { YJYGlobal.LogLine(openPositionsNotSent.Count + "/" + openPositions.Count + " (notSent/all) open positions."); } var messages = new List <Message>(); var posIds = new List <int>(); var groups = openPositionsNotSent.GroupBy(o => o.SecurityId).ToList(); foreach (var group in groups) //foreach security { var secId = group.Key; //YJYGlobal.LogLine("sec: " + secId + " alert_count: " + group.Count()); var prodDef = prodDefs.FirstOrDefault(o => o.Id == secId); var quote = quotes.FirstOrDefault(o => o.Id == secId); if (prodDef == null || quote == null) { YJYGlobal.LogLine("cannot find prodDef/quote " + secId); continue; } if (prodDef.QuoteType == enmQuoteType.Closed || prodDef.QuoteType == enmQuoteType.Inactive) { //YJYGlobal.LogLine("prod " + prodDef.Id + " quoteType is " + prodDef.QuoteType); continue; } //if (DateTime.UtcNow - quote.Time > _tolerance) //{ // YJYGlobal.LogLine("quote " + quote.Id + " too old " + quote.Time); // continue; //} ////get historical highest and lowest price //decimal highestBid; //decimal lowestAsk; //var ticks = redisTickClient.Lists[Ticks.GetTickListNamePrefix(TickSize.Raw) + prodDef.Id].GetAll(); //var dtUtcNow = DateTime.UtcNow; //if (!_lastFetchTill.ContainsKey(prodDef.Id)) //{s // var historyTicks = ticks.Select(o => o.Time > dtUtcNow - _tolerance).ToList(); //} var last = Quotes.GetLastPrice(quote); foreach (var p in group) //foreach alert belong to a security { //position goes to 0% var upl = Trades.CalculatePL(p, last, false); var inv = p.Invest.Value.ToString("0"); var lev = p.Leverage.Value.ToString("0"); var setPx = p.SettlePrice.Value.ToString("F" + prodDef.Prec); if (upl + p.Invest <= 0) { YJYGlobal.LogLine( $"position {p.Id} ({(p.Side.Value ? "↗" : "↘")} {inv}x{lev} at {setPx}) CLOSED at {last} PL {upl.ToString("0.00")}"); posIds.Add(p.Id); messages.Add(new Message(Serialization.ObjectToByteArray( new PosToClose() { Id = p.Id, closeType = PositionCloseType.Liquidate, closePx = last, closePxTime = quote.Time, }))); continue; } //stop if (p.StopPx != null) { if (p.Side.Value && last <= p.StopPx || !p.Side.Value && last >= p.StopPx) { YJYGlobal.LogLine( $"position {p.Id} ({(p.Side.Value ? "↗" : "↘")} {inv}x{lev} at {setPx}) STOPPED at {last} PL {upl.ToString("0.00")}"); posIds.Add(p.Id); messages.Add(new Message(Serialization.ObjectToByteArray( new PosToClose() { Id = p.Id, closeType = PositionCloseType.Stop, closePx = last, closePxTime = quote.Time, }))); continue; } } //take if (p.TakePx != null) { if (p.Side.Value && last >= p.TakePx || !p.Side.Value && last <= p.TakePx) { YJYGlobal.LogLine( $"position {p.Id} ({(p.Side.Value ? "↗" : "↘")} {inv}x{lev} at {setPx}) TAKEN at {last} PL {upl.ToString("0.00")}"); posIds.Add(p.Id); messages.Add(new Message(Serialization.ObjectToByteArray( new PosToClose() { Id = p.Id, closeType = PositionCloseType.Take, closePx = last, closePxTime = quote.Time, }))); continue; } } } //db.SaveChanges(); } if (messages.Count > 0) { _queueClient.SendAsync(messages); foreach (var posId in posIds) { _sentPosIds.Add(posId, DateTime.UtcNow); } } } } } catch (Exception e) { YJYGlobal.LogException(e); } //YJYGlobal.LogLine(""); Thread.Sleep(_sleepInterval); } }