/// <summary> /// Обработчик события получения позиции /// </summary> private async void PositionStatusReceived(AdapterEventArgs <PositionStatus> args) { using (LogManager.Scope()) { try { args.MarkHandled(); // Ищем счет для позиции string accountCode; using (accountsLock.ReadLock()) { if (!accountCodesById.TryGetValue(args.Message.account_id, out accountCode)) { Logger.Error().PrintFormat( "Unable to process position on contract #{0}: account #{1} is unknown", args.Message.contract_id, args.Message.account_id); return; } } // Обрабатываем метаданные контрактов if (args.Message.contract_metadata != null) { await instrumentResolver.HandleMetadataAsync(args.Message.contract_metadata, $"A position in \"{accountCode}\" account"); } // Ищем инструмент для позиции var instrument = instrumentResolver.GetInstrument(args.Message.contract_id); if (instrument == null) { Logger.Warn().PrintFormat( "Received a position on contract #{0} in account {1} but no matching instrument is found", args.Message.contract_id, accountCode); return; } // Рассчитываем позицию var position = new PositionMessage { Account = accountCode, Instrument = instrument }; var message = new StringBuilder(); message.AppendFormat("Position received: {0} [ ", instrument.Code); using (openPositionsLock.Lock()) { Dictionary <uint, Dictionary <int, OpenPosition> > d1; if (!openPositions.TryGetValue(args.Message.account_id, out d1)) { d1 = new Dictionary <uint, Dictionary <int, OpenPosition> >(); openPositions.Add(args.Message.account_id, d1); } Dictionary <int, OpenPosition> d2; if (!d1.TryGetValue(args.Message.contract_id, out d2)) { d2 = new Dictionary <int, OpenPosition>(); d1.Add(args.Message.contract_id, d2); } if (args.Message.is_snapshot) { d2.Clear(); } position.Quantity = 0; foreach (var p in args.Message.open_position) { var fmt = ObjectLogFormatter.Create(PrintOption.Nested, "CQGC_POSITION"); fmt.AddField(LogFieldNames.Id, p.id); fmt.AddField(LogFieldNames.Price, p.price); fmt.AddField(LogFieldNames.Quantity, p.qty); fmt.AddField(LogFieldNames.TradeDate, p.trade_date); fmt.AddField(LogFieldNames.TradeUtcTime, p.trade_utc_time); fmt.AddField(LogFieldNames.StatementDate, p.statement_date); message.Append(fmt.Print(PrintOption.Nested)); message.Append(", "); position.Quantity = (int)p.qty; position.Price = (decimal)p.price; d2[p.id] = p; } var volume = 0d; var quantity = 0u; foreach (var pair in d2) { volume += pair.Value.price * pair.Value.qty; quantity += pair.Value.qty; } position.Quantity = (int)quantity; position.Price = quantity != 0u ? (decimal)(volume / quantity) : 0; } if (args.Message.is_short_open_position) { position.Quantity *= -1; } message.Append("]: "); message.Append(LogFields.Price(position.Price)); message.Append(LogFields.Quantity(position.Quantity)); message.Append(LogFields.IsSnapshot(args.Message.is_snapshot)); Logger.Debug().Print(message.ToString().Preformatted()); // Отправляем сообщение OnMessageReceived(position); } catch (Exception e) { Logger.Error().Print(e, $"Failed to process {args.Message}"); } } }