private void InitPipeline() { var builder = new DisruptorPipelineBuilder(); _pipeline = builder.Build <Deal, Deal>(deal => { // count volume to balance ratio using (var ctx = new WatchdogDbContext()) { var dealEntity = ctx.Deals.First(d => d.Id == deal.Id); dealEntity.VolumeToBalanceRatio = deal.Volume / deal.Balance; ctx.SaveChanges(); } return(deal); }, 1).AddStep(deal => { // find connections based on rules using (var ctx = new WatchdogDbContext()) { // RULES DEFINITION - START var matches = ctx.Deals .Where(d => d.Id != deal.Id) .Where(d => DbFunctions.DiffSeconds(d.Date, deal.Date) < _openTimeDeltaInSeconds) .Where(d => d.SymbolId == deal.SymbolId) //.Where(d => d.VolumeToBalanceRatio) // TODO: what is the correct condition of the VtBR? .ToList(); // RULES DEFINITION - END if (matches.Any()) { var dealWithGroup = matches.FirstOrDefault(d => d.GroupId != null); var dealGroup = dealWithGroup != null ? dealWithGroup.Group : ctx.DealGroups.Add(new DealGroup()); var dealEntity = ctx.Deals.First(d => d.Id == deal.Id); dealEntity.Group = dealGroup; foreach (var match in matches) { match.Group = dealGroup; } // TODO: Cleanup empty groups, if any / could be scheduled as a periodic DB cleanup process ctx.SaveChanges(); // LOG it var sb = new StringBuilder($"Matches with [{deal}]:").AppendLine(); matches.ForEach(d => sb.AppendLine($" ==> [{d}]")); _logger.Log(sb.ToString()); } } return(true); }, 1).Create(); }
/// <summary> /// Start receiving new deal events and logging /// based on the set-up rules. /// </summary> public void Start() { for (int i = 0; i < _servers.Count; i++) { var server = _servers[i]; var eventsApiInst = _eventsApiInst[i]; var getBalanceApiInst = _getBalanceApiInst[i]; async void DealEvents_OnDealAddEventHandler(object control, CIMTDeal deal) { using (var ctx = new WatchdogDbContext()) { // get user from db var userLogin = (long)deal.Login(); var user = ctx.Users.FirstOrDefault(u => u.Login == userLogin) ?? ctx.Users.Add(new User { Login = userLogin, }); // get symbol from db var symbolName = deal.Symbol(); var symbol = ctx.Symbols.FirstOrDefault(s => s.Name == symbolName) ?? ctx.Symbols.Add(new Symbol { Name = symbolName }); var externalId = deal.Deal(); var dealType = ToDealType(deal.Action()); var volume = deal.Volume(); var fromMilliseconds = new DateTime(1970, 1, 1) + TimeSpan.FromMilliseconds(deal.TimeMsc()); var dealEntity = ctx.Deals.Add(new Deal { Symbol = symbol, User = user, ServerId = server.Id, ExternalId = (long)externalId, Type = dealType, Volume = (long)volume, Date = fromMilliseconds, }); dealEntity.Balance = getBalanceApiInst.GetUserBalance(deal.Login()); // TODO how to do this correctly? ctx.SaveChanges(); //_logger.Log($"Incoming deal: {dealEntity} (Time: {deal.Time()} || TimeMSC: {deal.TimeMsc()})"); _logger.Log($"Incoming deal: {dealEntity}"); await _pipeline.Execute(dealEntity); } } eventsApiInst.DealEvents.DealAddEventHandler += DealEvents_OnDealAddEventHandler; _logger.Log($"Starting connecting to [{server.Name}, {server.IpAddress}] ..."); var connectionParams = new ConnectionParams { IP = server.IpAddress, Login = (ulong)server.Login, Password = server.Password, Name = server.Name, }; getBalanceApiInst.Connect(connectionParams); eventsApiInst.Connect(connectionParams); } }