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), }; } } }