private void SessionOnOrderConfirmed(OEC.API.Order order, int oldOrderId)
		{
			//if (oldOrderId > 0)
			//{
			//	SendOutMessage(new ExecutionMessage
			//	{
			//		ExecutionType = ExecutionTypes.Order,
			//		OrderId = oldOrderId,
			//		OrderState = OrderStates.Done,
			//	});	
			//}

			//SendOutMessage(new ExecutionMessage
			//{
			//	ExecutionType = ExecutionTypes.Order,
			//	OrderId = order.ID,
			//	OrderStatus = OrderStatus.ReceiveByServer,
			//});
		}
		private void SessionOnContractChanged(OEC.API.Contract contract)
		{

		}
		private void SessionOnBarsReceived(Subscription subscription, OEC.API.Bar[] bars)
		{
			ProcessBars(subscription, bars, false);
		}
		private static string GetBoardCode(string exchange, OEC.API.Contract contract, string defaultBoardCode)
		{
			return exchange ?? contract.Exchange.Name ?? defaultBoardCode;
		}
		private void SessionOnContractsChanged(OEC.API.BaseContract contract)
		{

		}
		private void SessionOnHistoryReceived(Subscription subscription, OEC.API.Bar[] bars)
		{
			ProcessBars(subscription, bars, true);
		}
		private void SessionOnDealQuoteUpdated(OEC.API.DealQuote quote)
		{

		}
		private void SessionOnPriceTick(OEC.API.Contract contract, Price price)
		{
			ProcessContract(contract, 0);
		}
		private void SessionOnDomChanged(OEC.API.Contract contract)
		{
			ProcessContract(contract, 0);

			var dom = contract.DOM;

			var bids = new List<QuoteChange>();
			var asks = new List<QuoteChange>();

			var hasExchange = false;

			for (var i = 0; i < dom.BidExchanges.Length; i++)
			{
				var boardCode = GetBoardCode(dom.BidExchanges[i], contract, null);

				if (!hasExchange)
					hasExchange = !boardCode.IsEmpty() && boardCode != contract.Exchange.Name;

				bids.Add(new QuoteChange(Sides.Buy, contract.Cast(dom.BidLevels[i]) ?? 0, dom.BidSizes[i]) { BoardCode = boardCode });
			}

			for (var i = 0; i < dom.AskExchanges.Length; i++)
			{
				var boardCode = GetBoardCode(dom.AskExchanges[i], contract, null);

				if (!hasExchange)
					hasExchange = !boardCode.IsEmpty() && boardCode != contract.Exchange.Name;

				asks.Add(new QuoteChange(Sides.Sell, contract.Cast(dom.AskLevels[i]) ?? 0, dom.AskSizes[i]) { BoardCode = boardCode });
			}

			SendOutMessage(new QuoteChangeMessage
			{
				SecurityId = new SecurityId
				{
					SecurityCode = contract.Symbol,
					BoardCode = hasExchange ? AssociatedBoardCode : contract.Exchange.Name ?? AssociatedBoardCode
				},
				ServerTime = dom.LastUpdate.ApplyTimeZone(TimeHelper.Est),
				Bids = bids,
				Asks = asks,
			});
		}
		private void ProcessContract(OEC.API.Contract contract, long originalTransactionId)
		{
			SendOutMessage(new SecurityMessage
			{
				SecurityId = contract.ToSecurityId(),
				Name = contract.Name,
				UnderlyingSecurityCode = contract.BaseSymbol,
				Currency = contract.Currency.Name.ToCurrency(),
				Strike = contract.Strike.ToDecimal(),
				ExpiryDate = contract.HasExpiration ? contract.ExpirationDate.ApplyTimeZone(TimeHelper.Est) : (DateTimeOffset?)null,
				PriceStep = contract.TickSize.ToDecimal(),
				Decimals = contract.PriceFormat > 0 ? contract.PriceFormat : (int?)null,
				OptionType = contract.IsOption ? (contract.Put ? OptionTypes.Put : OptionTypes.Call) : (OptionTypes?)null,
				SecurityType = contract.GetSecurityType(),
				OriginalTransactionId = originalTransactionId,
			});
		}
		private void ProcessContract(OEC.API.Contract contract, Price currentPrice, long originalTransactionId)
		{
			ProcessContract(contract, originalTransactionId);

			if (currentPrice == null)
				return;

			SendOutMessage(new Level1ChangeMessage
			{
				SecurityId = contract.ToSecurityId(),
				ServerTime = currentPrice.LastDateTime.ApplyTimeZone(TimeHelper.Est),
			}
			.TryAdd(Level1Fields.LastTradePrice, contract.Cast(currentPrice.LastPrice))
			.TryAdd(Level1Fields.BestAskPrice, contract.Cast(currentPrice.AskPrice))
			.TryAdd(Level1Fields.BestAskVolume, (decimal)currentPrice.AskVol)
			.TryAdd(Level1Fields.BestBidPrice, contract.Cast(currentPrice.BidPrice))
			.TryAdd(Level1Fields.BestBidVolume, (decimal)currentPrice.BidVol)
			.TryAdd(Level1Fields.Change, contract.Cast(currentPrice.Change))
			.TryAdd(Level1Fields.OpenInterest, (decimal)currentPrice.OpenInterest)
			.TryAdd(Level1Fields.OpenPrice, contract.Cast(currentPrice.OpenPrice))
			.TryAdd(Level1Fields.HighPrice, contract.Cast(currentPrice.HighPrice))
			.TryAdd(Level1Fields.LowPrice, contract.Cast(currentPrice.LowPrice))
			.TryAdd(Level1Fields.LastTradeVolume, (decimal)currentPrice.LastVol)
			.TryAdd(Level1Fields.SettlementPrice, contract.Cast(currentPrice.Settlement))
			.TryAdd(Level1Fields.Volume, (decimal)currentPrice.TotalVol)
			.TryAdd(Level1Fields.StepPrice, (decimal)contract.ContractSize)
			.Add(Level1Fields.State, contract.GetSecurityState()));
		}
		private void SessionOnSymbolLookupReceived(OEC.API.SymbolLookupCriteria criteria, ContractList contracts)
		{
			var transId = _lookups.TryGetValue(criteria);

			foreach (var contract in contracts)
			{
				ProcessContract(contract, contract.CurrentPrice, transId);
			}

			SendOutMessage(new SecurityLookupResultMessage { OriginalTransactionId = transId });
		}
		private void SessionOnCommandUpdated(OEC.API.Order order, Command command)
		{
			//var msg = "Команда обновилась: #{0}, {1}-{2}, order #{3}".Put(command.ID, command.Type, command.State, oecOrder.OrderString());
			//this.AddInfoLog(msg);

			////ProcessEvents(() =>
			////{
			//var currentOrder = _orderMap.GetLocalOrder(oecOrder);

			//if (currentOrder == null)
			//	throw new OECException("CommandUpdated: Локальная заявка для OEC заявки '{0}' не найдена.".Put(oecOrder.OrderString()));

			//if (!(command.Type == CommandType.Modify || command.State == CommandState.Failed))
			//{
			//	// при необходимости будет обработано при получении OrderStateChanged
			//	currentOrder.Messages.Add(msg);
			//	return;
			//}

			//switch (command.State)
			//{
			//	case CommandState.Sent:
			//	{
			//		// Type == Modify
			//		var newOrder = _orderMap.GetLocalOrder(command.Version);
			//		if (newOrder == null)
			//			throw new OECException("CommandUpdated2: Локальная заявка для версии '{0}' не найдена.".Put(command.Version));

			//		if (command.ID > 0 && newOrder.Id <= 0)
			//		{
			//			var updatemsg = "OecCbOnCommandUpdated: Команда на модификацию (oldId={0}) принята сервером. newId={1}".Put(newOrder.Id, command.ID);
			//			this.AddInfoLog(updatemsg);

			//			GetOrder(newOrder.Security, newOrder.Type, command.ID, id => newOrder, order =>
			//			{
			//				_orderMap.BindOrderToOecOrderVersion(order, command.Version);
			//				order.Messages.Add(updatemsg);
			//				order.Status = OrderStatus.ReceiveByServer;

			//				return true;
			//			});
			//		}
			//		break;
			//	}
			//	case CommandState.Executed:
			//	{
			//		// Type == Modify
			//		var prevOecOrderVersion = oecOrder.Versions.Current.GetPreviousExecutedVersion();
			//		if (prevOecOrderVersion == null)
			//		{
			//			var errmsg = "Предыдущая версия заявки '{0}' не найдена.".Put(oecOrder.OrderString());
			//			this.AddErrorLog(errmsg);
			//			throw new OECException(errmsg);
			//		}

			//		var oldOrder = _orderMap.GetLocalOrder(prevOecOrderVersion);
			//		if (oldOrder == null)
			//			throw new OECException("CommandUpdated3: Локальная заявка для версии '{0}' не найдена.".Put(prevOecOrderVersion));

			//		OnModifyCommandExecuted(oldOrder, currentOrder, oecOrder);
			//		break;
			//	}
			//	case CommandState.Failed:
			//	{
			//		switch (command.Type)
			//		{
			//			case CommandType.Create:
			//				// will be handled in OnOrderChanged
			//				this.AddWarningLog("Команда Create вернула ошибку: {0}", command.ResultComments);
			//				break;
			//			case CommandType.Modify:
			//				var newOrder = _orderMap.GetLocalOrder(command.Version);
			//				if (newOrder == null)
			//					throw new OECException("CommandUpdated4: Локальная заявка для версии '{0}' не найдена.".Put(command.Version));

			//				newOrder.Id = 0;
			//				newOrder.State = OrderStates.Done;
			//				newOrder.Status = OrderStatus.NotValidated;
			//				newOrder.LastChangeTime = command.ResultTimestamp;

			//				RaiseOrderFailed(newOrder, new OECException("Команда Modify завершилась неудачно, комментарий='{0}'".Put(command.ResultComments)));
			//				break;
			//			case CommandType.Cancel:
			//				RaiseOrderFailed(currentOrder, new OECException("Команда Cancel завершилась неудачно, комментарий='{0}'".Put(command.ResultComments)));
			//				break;
			//		}
			//		break;
			//	}
			//}
			//});
		}
		private void SessionOnCompoundPositionGroupChanged(OEC.API.CompoundPositionGroup group, OEC.API.CompoundLegPosition position)
		{

		}
		private void SessionOnPriceChanged(OEC.API.Contract contract, Price price)
		{
			ProcessContract(contract, price, 0);
		}
		private void SessionOnSymbolLookupReceived(OEC.API.SymbolLookupCriteria criteria, ContractList contracts)
		{
			foreach (var contract in contracts)
			{
				ProcessContract(contract, contract.CurrentPrice, 0);
			}

			SendOutMessage(new SecurityLookupResultMessage());
		}
		private void SessionOnIndexComponentsReceived(OEC.API.Contract contract)
		{
			ProcessContract(contract, contract.CurrentPrice, 0);
		}
		private void ProcessContract(OEC.API.Contract contract, Price currentPrice, long originalTransactionId)
		{
			var secId = contract.ToSecurityId();
			
			SendOutMessage(new SecurityMessage
			{
				SecurityId = secId,
				Name = contract.Name,
				UnderlyingSecurityCode = contract.BaseSymbol,
				Currency = contract.Currency.Name.ToCurrency(),
				Strike = contract.Strike.ToDecimal(),
				ExpiryDate = contract.HasExpiration ? contract.ExpirationDate.ApplyTimeZone(TimeHelper.Est) : (DateTimeOffset?)null,
				PriceStep = contract.TickSize.ToDecimal(),
				Decimals = contract.PriceFormat > 0 ? contract.PriceFormat : (int?)null,
				OptionType = contract.IsOption ? (contract.Put ? OptionTypes.Put : OptionTypes.Call) : (OptionTypes?)null,
				SecurityType = contract.GetSecurityType(),
				OriginalTransactionId = originalTransactionId,
			});

			if (currentPrice == null)
				return;

			SendOutMessage(new Level1ChangeMessage
			{
				SecurityId = secId,
				ServerTime = currentPrice.LastDateTime.ApplyTimeZone(TimeHelper.Est),
			}
			.TryAdd(Level1Fields.LastTradePrice, contract.Cast(currentPrice.LastPrice))
			.TryAdd(Level1Fields.BestAskPrice, contract.Cast(currentPrice.AskPrice))
			.TryAdd(Level1Fields.BestAskVolume, (decimal)currentPrice.AskVol)
			.TryAdd(Level1Fields.BestBidPrice, contract.Cast(currentPrice.BidPrice))
			.TryAdd(Level1Fields.BestBidVolume, (decimal)currentPrice.BidVol)
			.TryAdd(Level1Fields.Change, contract.Cast(currentPrice.Change))
			.TryAdd(Level1Fields.OpenInterest, (decimal)currentPrice.OpenInterest)
			.TryAdd(Level1Fields.OpenPrice, contract.Cast(currentPrice.OpenPrice))
			.TryAdd(Level1Fields.HighPrice, contract.Cast(currentPrice.HighPrice))
			.TryAdd(Level1Fields.LowPrice, contract.Cast(currentPrice.LowPrice))
			.TryAdd(Level1Fields.LastTradeVolume, (decimal)currentPrice.LastVol)
			.TryAdd(Level1Fields.SettlementPrice, contract.Cast(currentPrice.Settlement))
			.TryAdd(Level1Fields.Volume, (decimal)currentPrice.TotalVol)
			.TryAdd(Level1Fields.StepPrice, (decimal)contract.ContractSize)
			.Add(Level1Fields.State, contract.GetSecurityState()));
		}
		private void SessionOnHistogramReceived(Subscription subscription, OEC.API.Histogram hist)
		{

		}
		private void SessionOnTicksReceived(Subscription subscription, OEC.API.Ticks ticks)
		{
			var contract = subscription.Contract;

			for (var i = 0; i < ticks.Exchanges.Length; i++)
			{
				SendOutMessage(new Level1ChangeMessage
				{
					SecurityId = new SecurityId
					{
						SecurityCode = contract.Symbol,
						BoardCode = GetBoardCode(ticks.Exchanges[i], contract, AssociatedBoardCode),
					},
					ServerTime = ticks.Timestamps[i].ApplyTimeZone(TimeHelper.Est)
				}
				.TryAdd(Level1Fields.LastTradePrice, contract.Cast(ticks.Prices[i]))
				.TryAdd(Level1Fields.LastTradeVolume, (decimal)ticks.Volumes32[i])
				.TryAdd(Level1Fields.BestBidPrice, contract.Cast(ticks.BidPrices[i]))
				.TryAdd(Level1Fields.BestAskPrice, contract.Cast(ticks.AskPrices[i])));	
			}
		}
		private void SessionOnDomChanged(OEC.API.Contract contract)
		{
			var dom = contract.DOM;

			var bids = new List<QuoteChange>();
			var asks = new List<QuoteChange>();

			for (var i = 0; i < dom.BidExchanges.Length; i++)
				bids.Add(new QuoteChange(Sides.Buy, contract.Cast(dom.BidLevels[i]) ?? 0, dom.BidSizes[i]) { BoardCode = GetBoardCode(dom.BidExchanges[i], contract, null) });

			for (var i = 0; i < dom.AskExchanges.Length; i++)
				asks.Add(new QuoteChange(Sides.Sell, contract.Cast(dom.AskLevels[i]) ?? 0, dom.AskSizes[i]) { BoardCode = GetBoardCode(dom.AskExchanges[i], contract, null) });

			SendOutMessage(new QuoteChangeMessage
			{
				SecurityId = new SecurityId
				{
					SecurityCode = contract.Symbol,
					BoardCode = AssociatedBoardCode
				},
				ServerTime = dom.LastUpdate.ApplyTimeZone(TimeHelper.Est),
				Bids = bids,
				Asks = asks,
			});
		}
		private void SessionOnUserStatusChanged(OEC.API.User status)
		{

		}
		private void SessionOnCurrencyPriceChanged(OEC.API.Currency currency, Price price)
		{

		}
		private void SessionOnUserMessage(OEC.API.User user, string message)
		{
			SendOutMessage(new Messages.NewsMessage
			{
				Source = user.Name,
				Headline = message,
				ServerTime = CurrentTime.Convert(TimeHelper.Est)
			});
		}
		private void SessionOnContractCreated(int requestId, OEC.API.Contract contract)
		{

		}
		private void SessionOnQuoteDetailsChanged(OEC.API.Contract contract)
		{

		}
		private void SessionOnContinuousContractRuleChanged(int requestId, OEC.API.ContinuousContractRule rule)
		{

		}
		private void SessionOnProductCalendarUpdated(OEC.API.BaseContract baseContract)
		{

		}
		private void ProcessBars(Subscription subscription, OEC.API.Bar[] bars, bool setFinished)
		{
			var key = _subscriptions.TryGetKey(subscription);

			var candleType = key == null ? typeof(TimeFrameCandleMessage) : GetCandleMessageType(key.Item2);

			var contract = subscription.Contract;

			foreach (var bar in bars)
			{
				var msg = candleType.CreateInstance<CandleMessage>();

				msg.SecurityId = new SecurityId
				{
					SecurityCode = contract.Symbol,
					BoardCode = contract.Exchange.Name,
				};
				msg.OpenTime = bar.Timestamp.ApplyTimeZone(TimeHelper.Est);
				msg.CloseTime = bar.CloseTimestamp.ApplyTimeZone(TimeHelper.Est);
				msg.OpenPrice = contract.Cast(bar.Open) ?? 0;
				msg.HighPrice = contract.Cast(bar.High) ?? 0;
				msg.LowPrice = contract.Cast(bar.Low) ?? 0;
				msg.ClosePrice = contract.Cast(bar.Close) ?? 0;
				msg.TotalVolume = bar.Volume64;
				msg.TotalTicks = bar.Ticks;
				msg.UpTicks = (int)bar.UpTicks;
				msg.DownTicks = (int)bar.DownTicks;
				msg.IsFinished = setFinished && bar == bars.Last();
				msg.State = CandleStates.Finished;

				SendOutMessage(msg);
			}
		}
		private void SessionOnOrderFilled(OEC.API.Order order, OEC.API.Fill fill)
		{
			if (!fill.Active)
				return;

			SendOutMessage(new ExecutionMessage
			{
				ExecutionType = ExecutionTypes.Transaction,
				OriginalTransactionId = _orderTransactions.TryGetValue2(order) ?? 0,
				OrderId = order.ID,
				TradeId = fill.ID,
				TradePrice = order.Contract.Cast(fill.Price),
				ServerTime = fill.Timestamp.ApplyTimeZone(TimeHelper.Est),
				TradeVolume = fill.Quantity,
				SystemComment = fill.Comments,
				Commission = fill.Commission.ToDecimal(),
			});
		}