namespace SampleHistoryTesting { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Windows; using System.Windows.Forms; using System.Windows.Media; using MessageBox = System.Windows.MessageBox; using Ecng.Common; using Ecng.Xaml; using Ecng.Collections; using StockSharp.Algo.Candles; using StockSharp.Algo.Candles.Compression; using StockSharp.Algo.Reporting; using StockSharp.Algo.Storages; using StockSharp.Algo.Strategies; using StockSharp.Algo.Testing; using StockSharp.Algo.Logging; using StockSharp.Algo.Indicators.Trend; using StockSharp.BusinessEntities; using StockSharp.Xaml; public partial class MainWindow { private Strategy _strategy; private ICollection _curveItems; private EmulationTrader _trader; private readonly LogManager _logManager = new LogManager(); private DateTime _startEmulationTime; public MainWindow() { InitializeComponent(); _logManager.Listeners.Add(new FileLogListener("log.txt")); HistoryPath.Text = "D:\\Program Files\\Hydra\\!Market_Data"; } private void FindPathClick(object sender, RoutedEventArgs e) { var dlg = new FolderBrowserDialog(); if (!HistoryPath.Text.IsEmpty()) dlg.SelectedPath = HistoryPath.Text; if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) { HistoryPath.Text = dlg.SelectedPath; } } private void StartBtnClick(object sender, RoutedEventArgs e) { // если процесс был запущен, то его останавливаем if (_trader != null && _trader.State != EmulationStates.Stopped) { StartBtn.IsEnabled = false; _strategy.Stop(); _trader.Stop(); _logManager.Sources.Clear(); return; } if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text)) { MessageBox.Show(this, "Неправильный путь."); return; } // создаем тестовый инструмент, на котором будет производится тестирование var security = new Security { Id = "RIU9@RTS", // по идентификатору инструмента будет искаться папка с историческими маркет данными Code = "RIU9", Name = "RTS-9.09", MinStepSize = 5, MinStepPrice = 2, Exchange = Exchange.Rts, }; security.Exchange.IsSupportAtomicReRegister = false; // тестовый портфель var portfolio = new Portfolio { Name = "test account", BeginValue = 1000000m }; // хранилище, через которое будет производиться доступ к тиковой и котировочной базе var storageRegistry = new StorageRegistry(); // изменяем путь, используемый по умолчанию ((LocalMarketDataDrive)storageRegistry.DefaultDrive).Path = HistoryPath.Text; var timeFrame = TimeSpan.FromMinutes(15); // в реальности период может быть другим, и это зависит от объема данных, // хранящихся по пути HistoryPath, var startTime = new DateTime(2009, 6, 1); var stopTime = new DateTime(2009, 8, 31); _trader = new EmulationTrader( new[] { security }, new[] { portfolio }) { MarketTimeChangedInterval = timeFrame, StorageRegistry = storageRegistry, // необходимо включать только если есть история стаканов и нужно получить более точное тестирование UseMarketDepth = true, //TradesKeepTime=new TimeSpan(3,0,0,0), }; // Задаем максимальную задержку принятия выставляемых заявок на бирже _trader.MarketEmulator.Settings.Latency = new TimeSpan(0, 0, 0, 0, 100); Exchange.Rts.TimeZoneInfo = TimeZoneInfo.Local; // история по стакана отсутствует, но стаканы необходимы для стратегии, // то их можно сгенерировать на основании цен последних сделок _trader.RegisterMarketDepth(new TrendMarketDepthGenerator(security) { // стакан для инструмента в истории обновляется раз в секунду Interval = TimeSpan.FromSeconds(1), }); // соединяемся с трейдером и запускаем экспорт, // чтобы инициализировать переданными инструментами и портфелями необходимые свойства EmulationTrader _trader.Connect(); _trader.StartExport(); var candleManager = new CandleManager(_trader); var candleManager30 = new CandleManager(_trader); candleManager.Sources.RemoveWhere(t => t.GetType() == typeof(TimeFrameCandleBuilder)); candleManager.Sources.Add(new myTimeFrameCandleBuilder { Sources = { new TradeCandleBuilderSource(_trader) } }); var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame); candleManager.Start(series); var series30 = new CandleSeries(typeof(TimeFrameCandle), security, TimeSpan.FromMinutes(30)); candleManager30.Start(series30); // создаем торговую стратегию, скользящие средние на 80 5-минуток и 10 5-минуток _strategy = new SmaStrategy(series, series30, new SimpleMovingAverage { Length = 80 }, new SimpleMovingAverage { Length = 10 })// { Volume = 1, Portfolio = portfolio, Security = security, Trader = _trader, }; // копируем параметры на визуальную панель ParametersPanel.Parameters.Clear(); ParametersPanel.Parameters.AddRange(_strategy.StatisticManager.Parameters); if (_curveItems == null) _curveItems = Curve.CreateCurve(_strategy.Name, Colors.DarkGreen); else _curveItems.Clear(); _strategy.PositionChanged += () => { var data = new EquityData { Time = _strategy.GetMarketTime(), Value = _strategy.PnL, }; this.GuiAsync(() => _curveItems.Add(data)); }; /* _strategy.PnLChanged += () => { var data = new EquityData { Time = _strategy.GetMarketTime(), Value = _strategy.PnL, }; this.GuiAsync(() => _curveItems.Add(data)); }; */ _logManager.Sources.Add(_strategy); // задаем шаг ProgressBar var progressStep = ((stopTime - startTime).Ticks / 100).To(); var nextTime = startTime + progressStep; TestingProcess.Maximum = 100; TestingProcess.Value = 0; // и подписываемся на событие изменения времени, чтобы обновить ProgressBar _trader.MarketTimeChanged += diff => { if (_trader.CurrentTime >= nextTime || _trader.CurrentTime >= stopTime) { nextTime += progressStep; this.GuiAsync(() => TestingProcess.Value++); } }; _trader.StateChanged += (oldState, newState) => { if (_trader.State == EmulationStates.Stopped) { this.GuiAsync(() => { StartBtn.IsEnabled = true; if (_trader.IsFinished) { TestingProcess.Value = TestingProcess.Maximum; MessageBox.Show("Закончено за " + (DateTime.Now - _startEmulationTime)); } else MessageBox.Show("Отменено"); }); } else if (_trader.State == EmulationStates.Started) { // запускаем стратегию когда эмулятор запустился _strategy.Start(); } }; Report.IsEnabled = true; _startEmulationTime = DateTime.Now; // запускаем эмуляцию, задавая период тестирования (startTime, stopTime). _trader.Start(startTime, stopTime); } private void ReportClick(object sender, RoutedEventArgs e) { // сгерерировать отчет по прошедшему тестированию // Внимание! сделок и заявок может быть большое количество, // поэтому Excel отчет может тормозить new ExcelStrategyReport(_strategy, "sma.xls").Generate(); // открыть отчет Process.Start("sma.xls"); } } }