namespace Ecng.Trading.Algo.Testing
{
	using System;
	using System.Collections.Generic;
	using Ecng.Trading.BusinessEntities;
	using Ecng.Common;
	/// 
	/// Настройки генератора стакана.
	/// 
	public class MarketDepthGeneratorSettings : GeneratorSettings
	{
		/// 
		/// Создать .
		/// 
		public MarketDepthGeneratorSettings()
		{
			this.MaxBidsDepth = 10;
			this.MaxAsksDepth = 10;
		}
		/// 
		/// Максимальная глубина бидов.
		/// 
		/// 
		/// Значение по умолчанию равно 10.
		/// 
		public int MaxBidsDepth { get; set; }
		/// 
		/// Максимальная глубина офферов.
		/// 
		/// 
		/// Значение по умолчанию равно 10.
		/// 
		public int MaxAsksDepth { get; set; }
	}
	/// 
	/// Генератор стакана случайным методом.
	/// 
	public class MarketDepthGenerator
	{
		/// 
		/// Создать .
		/// 
		public MarketDepthGenerator()
		{
			this.Settings = new MarketDepthGeneratorSettings();
		}
		/// 
		/// Настройки генератора.
		/// 
		public MarketDepthGeneratorSettings Settings { get; private set; }
		/// 
		/// Получить стартовую цену, относительно которой будет производится генерация стакана.
		/// 
		/// Инструмент.
		/// Стартовая цена.
		public virtual double GetSeedPrice(Security security)
		{
			if (security == null)
				throw new ArgumentNullException("security");
			double seedPrice = 0;
			if (security.LastTrade.Price != 0)
				seedPrice = security.LastTrade.Price;
			else if (security.BestBid.Price != 0)
				seedPrice = security.BestBid.Price + security.BestPair.SpreadPrice / 2;
			else if (security.BestAsk.Price != 0)
				seedPrice = security.BestAsk.Price - security.BestPair.SpreadPrice / 2;
			else if (security.ClosePrice != 0)
				seedPrice = security.ClosePrice;
			else if (security.OpenPrice != 0)
				seedPrice = security.OpenPrice;
			if (seedPrice == 0)
				throw new ArgumentException("Инструмент содержит недостаточно информации для генерации стакана.", "security");
			return seedPrice + RandomGen.GetInt(-this.Settings.MaxPriceStepCount, this.Settings.MaxPriceStepCount) * security.MinStepSize;
		}
		/// 
		/// Сгенерировать стакан.
		/// 
		/// Инструмент, стакан для которого необходимо сгенерировать.
		/// Сгенерированный стакан.
		public virtual MarketDepth Generate(Security security)
		{
			var marketDepth = new MarketDepth(security);
			Generate(marketDepth);
			return marketDepth;
		}
		/// 
		/// Сгенерировать стакан.
		/// 
		/// Стакан с котировками, которые необходимо обновить случайным образом.
		/// Сгенерированный стакан.
		public virtual void Generate(MarketDepth depth)
		{
			if (depth == null)
				throw new ArgumentNullException("depth");
			var bids = new List();
			var asks = new List();
			var seedPrice = GetSeedPrice(depth.Security);
			var lastBidPrice = seedPrice;
			var lastAskPrice = seedPrice;
			for (var i = 0; i < this.Settings.MaxBidsDepth; i++)
			{
				var quote = CreateQuote(lastBidPrice, depth.Security, OrderDirections.Buy);
				if (quote.Price <= 0)
					break;
				bids.Add(quote);
				lastBidPrice = quote.Price;
			}
			for (var i = 0; i < this.Settings.MaxAsksDepth; i++)
			{
				var quote = CreateQuote(lastAskPrice, depth.Security, OrderDirections.Sell);
				if (quote.Price <= 0)
					break;
				asks.Add(quote);
				lastAskPrice = quote.Price;
			}
			depth.Update(bids, asks, true);
		}
		private Quote CreateQuote(double startPrice, Security security, OrderDirections direction)
		{
			if (security == null)
				throw new ArgumentNullException("security");
			if (security.MinStepSize == 0)
				throw new ArgumentException("Минимальный шаг цены не может быть равен 0.", "security");
			return new Quote
			{
				OrderDirection = direction,
				Price = security.ShrinkPrice(startPrice + (direction == OrderDirections.Sell ? 1 : -1) * (RandomGen.GetInt(1, this.Settings.MaxPriceStepCount) * security.MinStepSize)),
				Security = security,
				Volume = RandomGen.GetInt(1, this.Settings.MaxVolume),
			};
		}
	}
}