Example #1
0
        static void Main(string[] args)
        {
            _candleManager = new CandleManager();

            if (!GetSetings())
                return;

            var storageRegistry = new StorageRegistry();
            ((LocalMarketDataDrive)storageRegistry.DefaultDrive).Path = _historyPath;

            var cbs = new TradeStorageCandleBuilderSource { StorageRegistry = storageRegistry };
            _candleManager.Sources.OfType<TimeFrameCandleBuilder>().Single().Sources.Add(cbs);


            

            _candleManager.Processing += GetCandles;


            foreach (var Sec in listOfName)
            {
                foreach (var timeFrame in listOfTimeFrame)
                {
                  
                   

                _series = new CandleSeries(typeof(TimeFrameCandle), Sec, timeFrame);

                LisfStreamWriters.Add(_series.ToString(), new StreamWriter(GetFileName(_series), false));


                _candleManager.Start(_series, _startTime, _endTime);

                


 
    }

            }

     

            Console.ReadKey();

            // Закроем все потоки которые мы записывали

            foreach (var strim in LisfStreamWriters)
            {
                strim.Value.Close();   
            }

        

        }
        public EMAStrategyOptimizer(Security security, StorageRegistry storage, Portfolio portfolio, DateTime startTime, DateTime stopTime)
        {
            _startTime = startTime;
            _stopTime = stopTime;

            _security = security;
            _portfolio = portfolio;

            _storage = storage;

            this.Volume = 1;
            this.UseQuoting = true;
        }
Example #3
0
		static void Main()
		{
			// создаем тестовый инструмент
			var security = new Security
			{
				Id = "TestId",
				PriceStep = 0.1m,
				Decimals = 1,
			};

			var trades = new List<Trade>();

			// генерируем 1000 произвольных сделок
			//

			for (var i = 0; i < 1000; i++)
			{
				var t = new Trade
				{
					Time = DateTime.Today + TimeSpan.FromMinutes(i),
					Id = i + 1,
					Security = security,
					Volume = RandomGen.GetInt(1, 10),
					Price = RandomGen.GetInt(1, 100) * security.PriceStep ?? 1m + 99
				};

				trades.Add(t);
			}

			var storage = new StorageRegistry();

			// получаем хранилище для тиковых сделок
			var tradeStorage = storage.GetTradeStorage(security);

			// сохраняем сделки
			tradeStorage.Save(trades);

			// загружаем сделки
			var loadedTrades = tradeStorage.Load(DateTime.Today, DateTime.Today + TimeSpan.FromMinutes(1000));

			foreach (var trade in loadedTrades)
			{
				Console.WriteLine(LocalizedStrings.Str2968Params, trade.Id, trade);
			}

			Console.ReadLine();

			// удаляем сделки (очищаем файл)
			tradeStorage.Delete(DateTime.Today, DateTime.Today + TimeSpan.FromMinutes(1000));
		}
Example #4
0
		public MainWindow()
		{
			InitializeComponent();

			this.LayoutManager = new LayoutManager(this, ProgrammaticDockSite);
			LayoutManager._layoutFile = Path.Combine(_settingsFolder, "layout.xml");

			ConnectCommand = new DelegateCommand(Connect, CanConnect);
			SettingsCommand = new DelegateCommand(Settings, CanSettings);

			Directory.CreateDirectory(_settingsFolder);

			var storageRegistry = new StorageRegistry {DefaultDrive = new LocalMarketDataDrive(_settingsFolder)};
			var securityStorage = storageRegistry.GetSecurityStorage();

			Connector = new Connector {EntityFactory = new StorageEntityFactory(securityStorage)};
			ConfigManager.RegisterService(new FilterableSecurityProvider(securityStorage));
			ConfigManager.RegisterService<IConnector>(Connector);
			ConfigManager.RegisterService<IMarketDataProvider>(Connector);

			_connectionFile = Path.Combine(_settingsFolder, "connection.xml");

			if (File.Exists(_connectionFile))
				Connector.Adapter.Load(new XmlSerializer<SettingsStorage>().Deserialize(_connectionFile));

			_secView = new SecuritiesView(this) {SecurityGrid = {MarketDataProvider = Connector}};

			Connector.NewSecurities += _secView.SecurityGrid.Securities.AddRange;

			Connector.MarketDepthsChanged += depths =>
			{
				foreach (var depth in depths)
				{
					var ctrl = _depths.TryGetValue(depth.Security);

					if (ctrl != null)
						ctrl.UpdateDepth(depth);
				}
			};
		}
        public KeyValuePair<OptVarItem, EMAEventModelStrategy> GetOptContext(OptVarItem optVarItem)
        {
            // clone doesn't work for some reason
            var security = new Security
            {
                Id = _security.Id,
                Code = _security.Code,
                Name = _security.Name,
                MinStepSize = _security.MinStepSize,
                MinStepPrice = _security.MinStepPrice,
                ExchangeBoard = _security.ExchangeBoard,
                MaxPrice = 99999,
                MinPrice = 1
            };

            // Create local Storage to make it disposable after optimization
            var storage = new StorageRegistry();
            ((LocalMarketDataDrive) storage.DefaultDrive).Path = ((LocalMarketDataDrive) _storage.DefaultDrive).Path;
            ((LocalMarketDataDrive) storage.DefaultDrive).UseAlphabeticPath = true;

            var portfolio = new Portfolio { BeginValue = _portfolio.BeginValue };

            EmulationTrader trader = new EmulationTrader(
                new[] { security },
                new[] { portfolio })
            {
                MarketTimeChangedInterval = optVarItem.TimeFrame,
                StorageRegistry = storage,
                UseMarketDepth = true,
                //UseCandlesTimeFrame = optVarItem.TimeFrame
            };

            if (trader.UseMarketDepth)
            {
                trader.MarketEmulator.Settings.DepthExpirationTime = TimeSpan.FromMinutes(5); // Default: TimeSpan.FromDays(1);
                var marketDepthGenerator = new TrendMarketDepthGenerator(security)
                {
                    // стакан для инструмента в истории обновляется раз в 10 секунд
                    Interval = TimeSpan.FromSeconds(10),
                    //MaxAsksDepth = 5,
                    //MaxBidsDepth = 5
                };

                trader.RegisterMarketDepth(marketDepthGenerator);

                trader.StateChanged += (oldState, newState) =>
                {
                    if (trader.State == EmulationStates.Stopped)
                    {
                        trader.UnRegisterMarketDepth(marketDepthGenerator);
                        marketDepthGenerator = null;
                    }
                };
            }

            // соединяемся с трейдером и запускаем экспорт,
            // чтобы инициализировать переданными инструментами и портфелями необходимые свойства EmulationTrader
            trader.Connect();
            trader.StartExport();

            var series = new CandleSeries(typeof(TimeFrameCandle), trader.Securities.First(), optVarItem.TimeFrame);
            var candleManager = new CandleManager(trader);
            candleManager.Start(series);

            var strategy = new EMAEventModelStrategy(series,
                new ExponentialMovingAverage { Length = optVarItem.FilterOptPeriod },
                new ExponentialMovingAverage { Length = optVarItem.LongOptPeriods },
                new ExponentialMovingAverage { Length = optVarItem.ShortOptPeriods },
                optVarItem.TakeProfitUnit, optVarItem.StopLossUnit)
            {
                Volume = this.Volume,
                Portfolio = portfolio,
                Security = security,
                Trader = trader,
                UseQuoting = this.UseQuoting
            };

            trader.StateChanged += (oldState, newState) =>
            {
                if (trader.State == EmulationStates.Started)
                {
                    strategy.Start();
                }
                else if (trader.State == EmulationStates.Stopped)
                {
                    strategy.Stop();
                    candleManager = null;
                    storage = null;
                }
            };

            var result = new KeyValuePair<OptVarItem, EMAEventModelStrategy>(optVarItem, strategy);
            return result;
        }
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            InitChart();

            if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text))
            {
                MessageBox.Show(this, LocalizedStrings.Str3014);
                return;
            }

            if (_connectors.Any(t => t.State != EmulationStates.Stopped))
            {
                MessageBox.Show(this, LocalizedStrings.Str3015);
                return;
            }

            var secIdParts = SecId.Text.Split('@');

            if (secIdParts.Length != 2)
            {
                MessageBox.Show(this, LocalizedStrings.Str3016);
                return;
            }

            var timeFrame = TimeSpan.FromMinutes(5);

            // создаем настройки для тестирования
            var settings = new[]
            {
                Tuple.Create(
                    TicksCheckBox,
                    TicksTestingProcess,
                    TicksParameterGrid,
                    // тест только на тиках
                    new EmulationInfo {
                    CurveColor = Colors.DarkGreen, StrategyName = LocalizedStrings.Str3017
                }),

                Tuple.Create(
                    TicksAndDepthsCheckBox,
                    TicksAndDepthsTestingProcess,
                    TicksAndDepthsParameterGrid,
                    // тест на тиках + стаканы
                    new EmulationInfo {
                    UseMarketDepth = true, CurveColor = Colors.Red, StrategyName = LocalizedStrings.Str3018
                }),

                Tuple.Create(
                    CandlesCheckBox,
                    CandlesTestingProcess,
                    CandlesParameterGrid,
                    // тест на свечах
                    new EmulationInfo {
                    UseCandleTimeFrame = timeFrame, CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.Str3019
                }),

                Tuple.Create(
                    CandlesAndDepthsCheckBox,
                    CandlesAndDepthsTestingProcess,
                    CandlesAndDepthsParameterGrid,
                    // тест на свечах + стаканы
                    new EmulationInfo {
                    UseMarketDepth = true, UseCandleTimeFrame = timeFrame, CurveColor = Colors.Cyan, StrategyName = LocalizedStrings.Str3020
                }),

                Tuple.Create(
                    OrderLogCheckBox,
                    OrderLogTestingProcess,
                    OrderLogParameterGrid,
                    // тест на логе заявок
                    new EmulationInfo {
                    UseOrderLog = true, CurveColor = Colors.CornflowerBlue, StrategyName = LocalizedStrings.Str3021
                })
            };

            // хранилище, через которое будет производиться доступ к тиковой и котировочной базе
            var storageRegistry = new StorageRegistry
            {
                // изменяем путь, используемый по умолчанию
                DefaultDrive = new LocalMarketDataDrive(HistoryPath.Text)
            };

            var startTime = (DateTime)From.Value;
            var stopTime  = (DateTime)To.Value;

            // ОЛ необходимо загружать с 18.45 пред дня, чтобы стаканы строились правильно
            if (OrderLogCheckBox.IsChecked == true)
            {
                startTime = startTime.Subtract(TimeSpan.FromDays(1)).AddHours(18).AddMinutes(45).AddTicks(1);
            }

            // задаем шаг ProgressBar
            var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>();

            // в реальности период может быть другим, и это зависит от объема данных,
            // хранящихся по пути HistoryPath,
            TicksTestingProcess.Maximum = TicksAndDepthsTestingProcess.Maximum = CandlesTestingProcess.Maximum = 100;
            TicksTestingProcess.Value   = TicksAndDepthsTestingProcess.Value = CandlesTestingProcess.Value = 0;

            var logManager      = new LogManager();
            var fileLogListener = new FileLogListener("sample.log");

            logManager.Listeners.Add(fileLogListener);
            //logManager.Listeners.Add(new DebugLogListener());	// чтобы смотреть логи в отладчике - работает медленно.

            var generateDepths = GenDepthsCheckBox.IsChecked == true;
            var maxDepth       = MaxDepth.Text.To <int>();
            var maxVolume      = MaxVolume.Text.To <int>();

            var secCode = secIdParts[0];
            var board   = ExchangeBoard.GetOrCreateBoard(secIdParts[1]);

            foreach (var set in settings)
            {
                if (set.Item1.IsChecked == false)
                {
                    continue;
                }

                var progressBar   = set.Item2;
                var statistic     = set.Item3;
                var emulationInfo = set.Item4;

                // создаем тестовый инструмент, на котором будет производится тестирование
                var security = new Security
                {
                    Id    = SecId.Text,                  // по идентификатору инструмента будет искаться папка с историческими маркет данными
                    Code  = secCode,
                    Board = board,
                };

                var level1Info = new Level1ChangeMessage
                {
                    SecurityId = security.ToSecurityId(),
                    ServerTime = startTime,
                }
                .TryAdd(Level1Fields.PriceStep, 10m)
                .TryAdd(Level1Fields.StepPrice, 6m)
                .TryAdd(Level1Fields.MinPrice, 10m)
                .TryAdd(Level1Fields.MaxPrice, 1000000m)
                .TryAdd(Level1Fields.MarginBuy, 10000m)
                .TryAdd(Level1Fields.MarginSell, 10000m);

                // тестовый портфель
                var portfolio = new Portfolio
                {
                    Name       = "test account",
                    BeginValue = 1000000,
                };

                // создаем подключение для эмуляции
                // инициализируем настройки (инструмент в истории обновляется раз в секунду)
                var connector = new HistoryEmulationConnector(
                    new[] { security },
                    new[] { portfolio })
                {
                    StorageRegistry = storageRegistry,

                    MarketEmulator =
                    {
                        Settings                =
                        {
                            // использовать свечи
                            UseCandlesTimeFrame = emulationInfo.UseCandleTimeFrame,

                            // сведение сделки в эмуляторе если цена коснулась нашей лимитной заявки.
                            // Если выключено - требуется "прохождение цены сквозь уровень"
                            // (более "суровый" режим тестирования.)
                            MatchOnTouch        = false,
                        }
                    },

                    //UseExternalCandleSource = true,
                    CreateDepthFromOrdersLog  = emulationInfo.UseOrderLog,
                    CreateTradesFromOrdersLog = emulationInfo.UseOrderLog,
                };

                connector.MarketDataAdapter.SessionHolder.MarketTimeChangedInterval = timeFrame;

                ((ILogSource)connector).LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info;

                logManager.Sources.Add(connector);

                connector.NewSecurities += securities =>
                {
                    //подписываемся на получение данных после получения инструмента

                    if (securities.All(s => s != security))
                    {
                        return;
                    }

                    // отправляем данные Level1 для инструмента
                    connector.MarketDataAdapter.SendOutMessage(level1Info);

                    // тест подразумевает наличие стаканов
                    if (emulationInfo.UseMarketDepth)
                    {
                        connector.RegisterMarketDepth(security);

                        if (
                            // если выбрана генерация стаканов вместо реальных стаканов
                            generateDepths ||
                            // для свечей генерируем стаканы всегда
                            emulationInfo.UseCandleTimeFrame != TimeSpan.Zero
                            )
                        {
                            // если история по стаканам отсутствует, но стаканы необходимы для стратегии,
                            // то их можно сгенерировать на основании цен последних сделок или свечек.
                            connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security))
                            {
                                Interval           = TimeSpan.FromSeconds(1),                       // стакан для инструмента в истории обновляется раз в секунду
                                MaxAsksDepth       = maxDepth,
                                MaxBidsDepth       = maxDepth,
                                UseTradeVolume     = true,
                                MaxVolume          = maxVolume,
                                MinSpreadStepCount = 2,                                 // минимальный генерируемый спред - 2 минимальных шага цены
                                MaxSpreadStepCount = 5,                                 // не генерировать спрэд между лучшим бид и аск больше чем 5 минимальных шагов цены - нужно чтобы при генерации из свечей не получалось слишком широкого спреда.
                                MaxPriceStepCount  = 3                                  // максимальное количество шагов между ценами,
                            });
                        }
                    }
                    else if (emulationInfo.UseOrderLog)
                    {
                        connector.RegisterOrderLog(security);
                    }
                };

                // соединяемся с трейдером и запускаем экспорт,
                // чтобы инициализировать переданными инструментами и портфелями необходимые свойства EmulationTrader
                connector.Connect();
                connector.StartExport();

                var candleManager = new CandleManager(connector);
                var series        = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);

                _shortMa = new SimpleMovingAverage {
                    Length = 10
                };
                _shortElem = new ChartIndicatorElement
                {
                    Color          = Colors.Coral,
                    ShowAxisMarker = false,
                    FullTitle      = _shortMa.ToString()
                };
                _bufferedChart.AddElement(_area, _shortElem);

                _longMa = new SimpleMovingAverage {
                    Length = 80
                };
                _longElem = new ChartIndicatorElement
                {
                    ShowAxisMarker = false,
                    FullTitle      = _longMa.ToString()
                };
                _bufferedChart.AddElement(_area, _longElem);

                // создаем торговую стратегию, скользящие средние на 80 5-минуток и 10 5-минуток
                var strategy = new SmaStrategy(_bufferedChart, _candlesElem, _tradesElem, _shortMa, _shortElem, _longMa, _longElem, series)
                {
                    Volume    = 1,
                    Portfolio = portfolio,
                    Security  = security,
                    Connector = connector,
                    LogLevel  = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info,

                    // по-умолчанию интервал равен 1 минут,
                    // что для истории в диапазон от нескольких месяцев излишне
                    UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>()
                };

                // комиссия в 1 копейку за сделку
                connector.MarketEmulator.SendInMessage(new CommissionRuleMessage
                {
                    Rule = new CommissionPerTradeRule {
                        Value = 0.01m
                    }
                });

                logManager.Sources.Add(strategy);

                // копируем параметры на визуальную панель
                statistic.Parameters.Clear();
                statistic.Parameters.AddRange(strategy.StatisticManager.Parameters);

                var pnlCurve           = Curve.CreateCurve("P&L " + emulationInfo.StrategyName, emulationInfo.CurveColor, EquityCurveChartStyles.Area);
                var unrealizedPnLCurve = Curve.CreateCurve(LocalizedStrings.PnLUnreal + emulationInfo.StrategyName, Colors.Black);
                var commissionCurve    = Curve.CreateCurve(LocalizedStrings.Str159 + " " + emulationInfo.StrategyName, Colors.Red, EquityCurveChartStyles.DashedLine);
                var posItems           = PositionCurve.CreateCurve(emulationInfo.StrategyName, emulationInfo.CurveColor);
                strategy.PnLChanged += () =>
                {
                    var pnl = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.PnL - strategy.Commission ?? 0
                    };

                    var unrealizedPnL = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.PnLManager.UnrealizedPnL
                    };

                    var commission = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.Commission ?? 0
                    };

                    pnlCurve.Add(pnl);
                    unrealizedPnLCurve.Add(unrealizedPnL);
                    commissionCurve.Add(commission);
                };

                strategy.PositionChanged += () => posItems.Add(new EquityData {
                    Time = strategy.CurrentTime, Value = strategy.Position
                });

                var nextTime = startTime + progressStep;

                // и подписываемся на событие изменения времени, чтобы обновить ProgressBar
                connector.MarketTimeChanged += d =>
                {
                    if (connector.CurrentTime < nextTime && connector.CurrentTime < stopTime)
                    {
                        return;
                    }

                    var steps = (connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1;
                    nextTime = startTime + (steps * progressStep.Ticks).To <TimeSpan>();
                    this.GuiAsync(() => progressBar.Value = steps);
                };

                connector.StateChanged += () =>
                {
                    if (connector.State == EmulationStates.Stopped)
                    {
                        candleManager.Stop(series);
                        strategy.Stop();

                        logManager.Dispose();
                        _connectors.Clear();

                        SetIsEnabled(false);

                        this.GuiAsync(() =>
                        {
                            if (connector.IsFinished)
                            {
                                progressBar.Value = progressBar.Maximum;
                                MessageBox.Show(LocalizedStrings.Str3024 + (DateTime.Now - _startEmulationTime));
                            }
                            else
                            {
                                MessageBox.Show(LocalizedStrings.cancelled);
                            }
                        });
                    }
                    else if (connector.State == EmulationStates.Started)
                    {
                        SetIsEnabled(true);

                        // запускаем стратегию когда эмулятор запустился
                        strategy.Start();
                        candleManager.Start(series);
                    }
                };

                if (ShowDepth.IsChecked == true)
                {
                    MarketDepth.UpdateFormat(security);

                    connector.NewMessage += (message, dir) =>
                    {
                        var quoteMsg = message as QuoteChangeMessage;

                        if (quoteMsg != null)
                        {
                            MarketDepth.UpdateDepth(quoteMsg);
                        }
                    };
                }

                _connectors.Add(connector);
            }

            _startEmulationTime = DateTime.Now;

            // запускаем эмуляцию
            foreach (var connector in _connectors)
            {
                // указываем даты начала и конца тестирования
                connector.Start(startTime, stopTime);
            }

            TabControl.Items.Cast <TabItem>().First(i => i.Visibility == Visibility.Visible).IsSelected = true;
        }
		private void StartEmulation()
		{
			if (_connector != null && _connector.State != EmulationStates.Stopped)
				throw new InvalidOperationException(LocalizedStrings.Str3015);

			if (Strategy == null)
				throw new InvalidOperationException("Strategy not selected.");

			var strategy = (EmulationDiagramStrategy)Strategy;

			if (strategy.DataPath.IsEmpty() || !Directory.Exists(strategy.DataPath))
				throw new InvalidOperationException(LocalizedStrings.Str3014);

			strategy
				.Composition
				.Parameters
				.ForEach(p =>
				{
					if (p.Type == typeof(Security) && p.Value == null)
						throw new InvalidOperationException(LocalizedStrings.Str1380);
				});

			strategy.Reset();
			Reset();

			var securityId = "empty@empty";
			var secGen = new SecurityIdGenerator();
			var secIdParts = secGen.Split(securityId);
			var secCode = secIdParts.SecurityCode;
			var board = ExchangeBoard.GetOrCreateBoard(secIdParts.BoardCode);
			var timeFrame = strategy.CandlesTimeFrame;
			var useCandles = strategy.MarketDataSource == MarketDataSource.Candles;

			// create test security
			var security = new Security
			{
				Id = securityId, // sec id has the same name as folder with historical data
				Code = secCode,
				Board = board,
			};

			// storage to historical data
			var storageRegistry = new StorageRegistry
			{
				// set historical path
				DefaultDrive = new LocalMarketDataDrive(strategy.DataPath)
			};

			var startTime = strategy.StartDate.ChangeKind(DateTimeKind.Utc);
			var stopTime = strategy.StopDate.ChangeKind(DateTimeKind.Utc);

			// ProgressBar refresh step
			var progressStep = ((stopTime - startTime).Ticks / 100).To<TimeSpan>();

			// set ProgressBar bounds
			TicksAndDepthsProgress.Value = 0;
			TicksAndDepthsProgress.Maximum = 100;

			// test portfolio
			var portfolio = new Portfolio
			{
				Name = "test account",
				BeginValue = 1000000,
			};

			var securityProvider = ConfigManager.GetService<ISecurityProvider>();

			// create backtesting connector
			_connector = new HistoryEmulationConnector(securityProvider, new[] { portfolio }, new StorageRegistry())
			{
				EmulationAdapter =
				{
					Emulator =
					{
						Settings =
						{
							// match order if historical price touched our limit order price. 
							// It is terned off, and price should go through limit order price level
							// (more "severe" test mode)
							MatchOnTouch = false,
						}
					}
				},

				UseExternalCandleSource = useCandles,

				HistoryMessageAdapter =
				{
					StorageRegistry = storageRegistry,

					// set history range
					StartDate = startTime,
					StopDate = stopTime,
				},

				// set market time freq as time frame
				MarketTimeChangedInterval = timeFrame,
			};

			//((ILogSource)_connector).LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info;

			ConfigManager.GetService<LogManager>().Sources.Add(_connector);

			var candleManager = new CandleManager(_connector);

			strategy.Volume = 1;
			strategy.Portfolio = portfolio;
			strategy.Security = security;
			strategy.Connector = _connector;
			//LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info,

			// by default interval is 1 min,
			// it is excessively for time range with several months
			strategy.UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To<TimeSpan>();

			strategy.SetCandleManager(candleManager);

			_connector.NewSecurity += s =>
			{
				var level1Info = new Level1ChangeMessage
				{
					SecurityId = s.ToSecurityId(),
					ServerTime = startTime,
				}
					.TryAdd(Level1Fields.PriceStep, secIdParts.SecurityCode == "RIZ2" ? 10m : 1)
					.TryAdd(Level1Fields.StepPrice, 6m)
					.TryAdd(Level1Fields.MinPrice, 10m)
					.TryAdd(Level1Fields.MaxPrice, 1000000m)
					.TryAdd(Level1Fields.MarginBuy, 10000m)
					.TryAdd(Level1Fields.MarginSell, 10000m);

				// fill level1 values
				_connector.SendInMessage(level1Info);

				//_connector.RegisterMarketDepth(security);

				//if (!useCandles)
				//	_connector.RegisterTrades(s);
			};

			var nextTime = startTime + progressStep;

			// handle historical time for update ProgressBar
			_connector.MarketTimeChanged += d =>
			{
				if (_connector.CurrentTime < nextTime && _connector.CurrentTime < stopTime)
					return;

				var steps = (_connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1;
				nextTime = startTime + (steps * progressStep.Ticks).To<TimeSpan>();
				this.GuiAsync(() => TicksAndDepthsProgress.Value = steps);
			};

			_connector.LookupSecuritiesResult += (ss) =>
			{
				if (strategy.ProcessState != ProcessStates.Stopped)
					return;

				// start strategy before emulation started
				strategy.Start();

				// start historical data loading when connection established successfully and all data subscribed
				_connector.Start();
			};

			_connector.StateChanged += () =>
			{
				switch (_connector.State)
				{
					case EmulationStates.Stopped:
						strategy.Stop();

						this.GuiAsync(() =>
						{
							if (_connector.IsFinished)
								TicksAndDepthsProgress.Value = TicksAndDepthsProgress.Maximum;
						});
						break;
					case EmulationStates.Started:
						break;
				}
			};

			TicksAndDepthsProgress.Value = 0;

			DiagramDebuggerControl.Debugger.IsEnabled = true;

			// raise NewSecurities and NewPortfolio for full fill strategy properties
			_connector.Connect();

			// 1 cent commission for trade
			_connector.SendInMessage(new CommissionRuleMessage
			{
				Rule = new CommissionPerTradeRule
				{
					Value = 0.01m
				}
			});
		}
Example #8
0
		private void StartBtnClick(object sender, RoutedEventArgs e)
		{
			InitChart();

			if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text))
			{
				MessageBox.Show(this, LocalizedStrings.Str3014);
				return;
			}

			if (_connectors.Any(t => t.State != EmulationStates.Stopped))
			{
				MessageBox.Show(this, LocalizedStrings.Str3015);
				return;
			}

			var secIdParts = SecId.Text.Split('@');

			if (secIdParts.Length != 2)
			{
				MessageBox.Show(this, LocalizedStrings.Str3016);
				return;
			}

			var timeFrame = TimeSpan.FromMinutes(5);

			// create backtesting modes
			var settings = new[]
			{
				Tuple.Create(
					TicksCheckBox,
					TicksTestingProcess,
					TicksParameterGrid,
					// ticks
					new EmulationInfo {UseTicks = true, CurveColor = Colors.DarkGreen, StrategyName = LocalizedStrings.Ticks}),

				Tuple.Create(
					TicksAndDepthsCheckBox,
					TicksAndDepthsTestingProcess,
					TicksAndDepthsParameterGrid,
					// ticks + order book
					new EmulationInfo {UseTicks = true, UseMarketDepth = true, CurveColor = Colors.Red, StrategyName = LocalizedStrings.XamlStr757}),

				Tuple.Create(
					DepthsCheckBox,
					DepthsTestingProcess,
					DepthsParameterGrid,
					// order book
					new EmulationInfo {UseMarketDepth = true, CurveColor = Colors.OrangeRed, StrategyName = LocalizedStrings.MarketDepths}),


				Tuple.Create(
					CandlesCheckBox,
					CandlesTestingProcess,
					CandlesParameterGrid,
					// candles
					new EmulationInfo {UseCandleTimeFrame = timeFrame, CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.Candles}),
				
				Tuple.Create(
					CandlesAndDepthsCheckBox,
					CandlesAndDepthsTestingProcess,
					CandlesAndDepthsParameterGrid,
					// candles + orderbook
					new EmulationInfo {UseMarketDepth = true, UseCandleTimeFrame = timeFrame, CurveColor = Colors.Cyan, StrategyName = LocalizedStrings.XamlStr635}),
			
				Tuple.Create(
					OrderLogCheckBox,
					OrderLogTestingProcess,
					OrderLogParameterGrid,
					// order log
					new EmulationInfo {UseOrderLog = true, CurveColor = Colors.CornflowerBlue, StrategyName = LocalizedStrings.OrderLog})
			};

			// storage to historical data
			var storageRegistry = new StorageRegistry
			{
				// set historical path
				DefaultDrive = new LocalMarketDataDrive(HistoryPath.Text)
			};

			var startTime = ((DateTime)From.Value).ChangeKind(DateTimeKind.Utc);
			var stopTime = ((DateTime)To.Value).ChangeKind(DateTimeKind.Utc);

			// ОЛ необходимо загружать с 18.45 пред дня, чтобы стаканы строились правильно
			if (OrderLogCheckBox.IsChecked == true)
				startTime = startTime.Subtract(TimeSpan.FromDays(1)).AddHours(18).AddMinutes(45).AddTicks(1);

			// ProgressBar refresh step
			var progressStep = ((stopTime - startTime).Ticks / 100).To<TimeSpan>();

			// set ProgressBar bounds
			_progressBars.ForEach(p =>
			{
				p.Value = 0;
				p.Maximum = 100;
			});
			
			var logManager = new LogManager();
			var fileLogListener = new FileLogListener("sample.log");
			logManager.Listeners.Add(fileLogListener);
			//logManager.Listeners.Add(new DebugLogListener());	// for track logs in output window in Vusial Studio (poor performance).

			var generateDepths = GenDepthsCheckBox.IsChecked == true;
			var maxDepth = MaxDepth.Text.To<int>();
			var maxVolume = MaxVolume.Text.To<int>();

			var secCode = secIdParts[0];
			var board = ExchangeBoard.GetOrCreateBoard(secIdParts[1]);

			foreach (var set in settings)
			{
				if (set.Item1.IsChecked == false)
					continue;

				var progressBar = set.Item2;
				var statistic = set.Item3;
				var emulationInfo = set.Item4;

				// create test security
				var security = new Security
				{
					Id = SecId.Text, // sec id has the same name as folder with historical data
					Code = secCode,
					Board = board,
				};

				var level1Info = new Level1ChangeMessage
				{
					SecurityId = security.ToSecurityId(),
					ServerTime = startTime,
				}
				.TryAdd(Level1Fields.PriceStep, 10m)
				.TryAdd(Level1Fields.StepPrice, 6m)
				.TryAdd(Level1Fields.MinPrice, 10m)
				.TryAdd(Level1Fields.MaxPrice, 1000000m)
				.TryAdd(Level1Fields.MarginBuy, 10000m)
				.TryAdd(Level1Fields.MarginSell, 10000m);

				// test portfolio
				var portfolio = new Portfolio
				{
					Name = "test account",
					BeginValue = 1000000,
				};

				// create backtesting connector
				var connector = new HistoryEmulationConnector(
					new[] { security },
					new[] { portfolio })
				{
					MarketEmulator =
					{
						Settings =
						{
							// match order if historical price touched our limit order price. 
							// It is terned off, and price should go through limit order price level
							// (more "severe" test mode)
							MatchOnTouch = false,
						}
					},

					UseExternalCandleSource = emulationInfo.UseCandleTimeFrame != null,

					CreateDepthFromOrdersLog = emulationInfo.UseOrderLog,
					CreateTradesFromOrdersLog = emulationInfo.UseOrderLog,

					HistoryMessageAdapter =
					{
						StorageRegistry = storageRegistry,

						// set history range
						StartDate = startTime,
						StopDate = stopTime,
					},

					// set market time freq as time frame
					MarketTimeChangedInterval = timeFrame,
				};

				((ILogSource)connector).LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info;

				logManager.Sources.Add(connector);

				var candleManager = emulationInfo.UseCandleTimeFrame == null
					? new CandleManager(new TradeCandleBuilderSourceEx(connector))
					: new CandleManager(connector);

				var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);

				_shortMa = new SimpleMovingAverage { Length = 10 };
				_shortElem = new ChartIndicatorElement
				{
					Color = Colors.Coral,
					ShowAxisMarker = false,
					FullTitle = _shortMa.ToString()
				};
				_bufferedChart.AddElement(_area, _shortElem);

				_longMa = new SimpleMovingAverage { Length = 80 };
				_longElem = new ChartIndicatorElement
				{
					ShowAxisMarker = false,
					FullTitle = _longMa.ToString()
				};
				_bufferedChart.AddElement(_area, _longElem);

				// create strategy based on 80 5-min и 10 5-min
				var strategy = new SmaStrategy(_bufferedChart, _candlesElem, _tradesElem, _shortMa, _shortElem, _longMa, _longElem, series)
				{
					Volume = 1,
					Portfolio = portfolio,
					Security = security,
					Connector = connector,
					LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info,

					// by default interval is 1 min,
					// it is excessively for time range with several months
					UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To<TimeSpan>()
				};

				logManager.Sources.Add(strategy);

				connector.NewSecurities += securities =>
				{
					if (securities.All(s => s != security))
						return;

					// fill level1 values
					connector.SendInMessage(level1Info);

					if (emulationInfo.UseMarketDepth)
					{
						connector.RegisterMarketDepth(security);

						if (
								// if order book will be generated
								generateDepths ||
								// of backtesting will be on candles
								emulationInfo.UseCandleTimeFrame != TimeSpan.Zero
							)
						{
							// if no have order book historical data, but strategy is required,
							// use generator based on last prices
							connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security))
							{
								Interval = TimeSpan.FromSeconds(1), // order book freq refresh is 1 sec
								MaxAsksDepth = maxDepth,
								MaxBidsDepth = maxDepth,
								UseTradeVolume = true,
								MaxVolume = maxVolume,
								MinSpreadStepCount = 2,	// min spread generation is 2 pips
								MaxSpreadStepCount = 5,	// max spread generation size (prevent extremely size)
								MaxPriceStepCount = 3	// pips size,
							});
						}
					}

					if (emulationInfo.UseOrderLog)
					{
						connector.RegisterOrderLog(security);
					}

					if (emulationInfo.UseTicks)
					{
						connector.RegisterTrades(security);
					}

					// start strategy before emulation started
					strategy.Start();
					candleManager.Start(series);

					// start historical data loading when connection established successfully and all data subscribed
					connector.Start();
				};

				// fill parameters panel
				statistic.Parameters.Clear();
				statistic.Parameters.AddRange(strategy.StatisticManager.Parameters);

				var pnlCurve = Curve.CreateCurve("P&L " + emulationInfo.StrategyName, emulationInfo.CurveColor, EquityCurveChartStyles.Area);
				var unrealizedPnLCurve = Curve.CreateCurve(LocalizedStrings.PnLUnreal + emulationInfo.StrategyName, Colors.Black);
				var commissionCurve = Curve.CreateCurve(LocalizedStrings.Str159 + " " + emulationInfo.StrategyName, Colors.Red, EquityCurveChartStyles.DashedLine);
				var posItems = PositionCurve.CreateCurve(emulationInfo.StrategyName, emulationInfo.CurveColor);
				strategy.PnLChanged += () =>
				{
					var pnl = new EquityData
					{
						Time = strategy.CurrentTime,
						Value = strategy.PnL - strategy.Commission ?? 0
					};

					var unrealizedPnL = new EquityData
					{
						Time = strategy.CurrentTime,
						Value = strategy.PnLManager.UnrealizedPnL
					};

					var commission = new EquityData
					{
						Time = strategy.CurrentTime,
						Value = strategy.Commission ?? 0
					};

					pnlCurve.Add(pnl);
					unrealizedPnLCurve.Add(unrealizedPnL);
					commissionCurve.Add(commission);
				};

				strategy.PositionChanged += () => posItems.Add(new EquityData { Time = strategy.CurrentTime, Value = strategy.Position });

				var nextTime = startTime + progressStep;

				// handle historical time for update ProgressBar
				connector.MarketTimeChanged += d =>
				{
					if (connector.CurrentTime < nextTime && connector.CurrentTime < stopTime)
						return;

					var steps = (connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1;
					nextTime = startTime + (steps * progressStep.Ticks).To<TimeSpan>();
					this.GuiAsync(() => progressBar.Value = steps);
				};

				connector.StateChanged += () =>
				{
					if (connector.State == EmulationStates.Stopped)
					{
						candleManager.Stop(series);
						strategy.Stop();

						logManager.Dispose();
						_connectors.Clear();

						SetIsEnabled(false);

						this.GuiAsync(() =>
						{
							if (connector.IsFinished)
							{
								progressBar.Value = progressBar.Maximum;
								MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime));
							}
							else
								MessageBox.Show(this, LocalizedStrings.cancelled);
						});
					}
					else if (connector.State == EmulationStates.Started)
					{
						SetIsEnabled(true);
					}
				};

				if (ShowDepth.IsChecked == true)
				{
					MarketDepth.UpdateFormat(security);

					connector.NewMessage += message =>
					{
						var quoteMsg = message as QuoteChangeMessage;

						if (quoteMsg != null)
							MarketDepth.UpdateDepth(quoteMsg);
					};
				}

				_connectors.Add(connector);

				progressBar.Value = 0;
			}

			_startEmulationTime = DateTime.Now;

			// start emulation
			foreach (var connector in _connectors)
			{
				// raise NewSecurities and NewPortfolio for full fill strategy properties
				connector.Connect();

				// 1 cent commission for trade
				connector.SendInMessage(new CommissionRuleMessage
				{
					Rule = new CommissionPerTradeRule { Value = 0.01m }
				});
			}

			TabControl.Items.Cast<TabItem>().First(i => i.Visibility == Visibility.Visible).IsSelected = true;
		}
Example #9
0
        private void OnHistoryStartClick(object sender, RoutedEventArgs e)
        {
            btnHistoryStart.IsEnabled = false;
            this.InitGrids();

            // создаем тестовый инструмент, на котором будет производится тестирование
            var security = new Security
            {
                Id = this.txtSecurityId.Text, // по идентификатору инструмента будет искаться папка с историческими маркет данными
                Code = this.txtSecurityCode.Text,
                Name = this.txtSecurityCode.Text,
                MinPrice = 1,
                MaxPrice = 99999,
                MinStepSize = 1,
                MinStepPrice = 1,
                ExchangeBoard = ExchangeBoard.Forts,
            };

            security.ExchangeBoard.IsSupportAtomicReRegister = false; // fixed quoting reregister error

            var storageRegistry = new StorageRegistry();
            ((LocalMarketDataDrive) storageRegistry.DefaultDrive).Path = this.txtHistoryPath.Text;
            ((LocalMarketDataDrive) storageRegistry.DefaultDrive).UseAlphabeticPath = true;

            var portfolio = new Portfolio { Name = "test account", BeginValue = 30000m };

            DateTime startTime;
            DateTime stopTime;

            if (!DateTime.TryParse(txtHistoryRangeEnd.Text, out stopTime))
            {
                stopTime = DateTime.Now;
                txtHistoryRangeEnd.Text = stopTime.ToString();
            }

            if (!DateTime.TryParse(txtHistoryRangeBegin.Text, out startTime))
            {
                startTime = stopTime.AddDays(-3);
                txtHistoryRangeBegin.Text = startTime.ToString();
            }

            EMAStrategyOptimizer optimizer = new EMAStrategyOptimizer(security, storageRegistry, portfolio, startTime, stopTime)
            {
                Volume = this.Volume,
                Log = _log
            };

            var context = optimizer.GetOptContext(this.MainOptVarItem);
            _trader = context.Value.Trader;
            _strategy = context.Value;

            this.InitChart(_strategy);

            _strategy.Trader.NewOrders += orders => orders.ForEach(OnOrderRegistered);
            _strategy.Trader.NewMyTrades += OnNewTrades;

            _logManager.Sources.Add(_strategy);

            // устанавливаем в визуальный элемент ProgressBar максимальное количество итераций)
            this.pbHistoryTestProgress.Maximum = 10;
            this.pbHistoryTestProgress.Value = 0;

            var totalMinutes = (stopTime - startTime).TotalMinutes;
            var segment = Math.Floor(totalMinutes / 10);
            var nSegment = 1;
            var sSegment = segment;
            _trader.MarketTimeChanged += span =>
            {
                var currentMinute = (_trader.CurrentTime - startTime).TotalMinutes;
                if (currentMinute >= sSegment || _trader.CurrentTime >= stopTime)
                {
                    nSegment += 1;
                    sSegment = segment * nSegment;

                    this.GuiAsync(() =>
                    {
                        this.pbHistoryTestProgress.Value = nSegment;
                        this.UpdateStrategyStat(_strategy);
                    });
                }
            };

            Stopwatch sw = new Stopwatch();

            ((EmulationTrader)_trader).StateChanged += (states, emulationStates) =>
            {
                if (((EmulationTrader)_trader).State == EmulationStates.Stopped)
                {
                    sw.Stop();

                    this.GuiAsync(() =>
                    {
                        this.UpdateStrategyStat(_strategy);
                        _strategy.CandleSeries.GetCandles<TimeFrameCandle>().ForEach(DrawCandleAndEma);
                        _strategy.Trader.MyTrades.ForEach(DrawTrade);

                        this.pbHistoryTestProgress.Value = 0;
                        btnHistoryStart.IsEnabled = true;
                    });

                    // clean stupid dictionary
                    //var value = _trader.GetType().GetField("#=qUTBJ0c9uFmGWYx4a3_oZjOoV9pJDtArCh9oL5k$U8DQ=", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(_trader);
                    //value.GetType().GetMethod("Clear").Invoke(value, null);

                    _log.AddLog(new LogMessage(_log, DateTime.Now, LogLevels.Info,
                                               String.Format("History testing done ({0}). Result: PnL: {1}, {2}",
                                                             sw.Elapsed,
                                                             _strategy.PnLManager.PnL,
                                                             this.MainOptVarItem
                                                   )));
                }
                else if (((EmulationTrader)_trader).State == EmulationStates.Started)
                {
                    sw.Start();
                }
            };

            // соединяемся с трейдером и запускаем экспорт,
            // чтобы инициализировать переданными инструментами и портфелями необходимые свойства EmulationTrader
            _trader.Connect();
            _trader.StartExport();

            // запускаем эмуляцию, задавая период тестирования (startTime, stopTime).
            ((EmulationTrader)_trader).Start(startTime, stopTime);
        }
Example #10
0
        protected override TimeSpan OnProcess()
        {
            // если фильтр по инструментам выключен (выбран инструмент все инструменты)
            if (this.GetAllSecurity() != null)
            {
                //throw new InvalidOperationException("Источник не поддерживает закачку данных по всем инструментам.");
                this.AddWarningLog(LocalizedStrings.Str2292);
                return(TimeSpan.MaxValue);
            }

            var source = new AlorHistorySource();

            if (_settings.UseTemporaryFiles != TempFiles.NotUse)
            {
                source.DumpFolder = GetTempPath();
            }

            var startDate = _settings.StartFrom;
            var endDate   = DateTime.Today - TimeSpan.FromDays(_settings.Offset);

            var allDates = startDate.Range(endDate, TimeSpan.FromDays(1)).ToArray();

            foreach (var security in GetWorkingSecurities())
            {
                if (!CanProcess())
                {
                    break;
                }

                #region LoadCandles
                if (security.CandleSeries.Any())
                {
                    foreach (var series in security.CandleSeries)
                    {
                        if (!CanProcess())
                        {
                            break;
                        }

                        if (series.CandleType != typeof(TimeFrameCandle))
                        {
                            this.AddWarningLog(LocalizedStrings.Str2296Params, series);
                            continue;
                        }

                        var storage    = StorageRegistry.GetCandleStorage(series.CandleType, security.Security, series.Arg, _settings.Drive, _settings.StorageFormat);
                        var emptyDates = allDates.Except(storage.Dates).ToArray();

                        if (emptyDates.IsEmpty())
                        {
                            this.AddInfoLog(LocalizedStrings.Str2297Params, series.Arg, security.Security.Id);
                            continue;
                        }

                        foreach (var emptyDate in emptyDates)
                        {
                            if (!CanProcess())
                            {
                                break;
                            }

                            if (_settings.IgnoreWeekends && !security.IsTradeDate(emptyDate))
                            {
                                this.AddDebugLog(LocalizedStrings.WeekEndDate, emptyDate);
                                continue;
                            }

                            try
                            {
                                this.AddInfoLog(LocalizedStrings.Str2298Params, series.Arg, emptyDate, security.Security.Id);
                                var candles = source.GetCandles(security.Security, (TimeSpan)series.Arg, emptyDate, emptyDate);

                                if (candles.Any())
                                {
                                    SaveCandles(security, candles);
                                }
                                else
                                {
                                    this.AddDebugLog(LocalizedStrings.NoData);
                                }

                                if (_settings.UseTemporaryFiles == TempFiles.UseAndDelete)
                                {
                                    File.Delete(source.GetDumpFile(security.Security, emptyDate, emptyDate, typeof(TimeFrameCandle), series.Arg));
                                }
                            }
                            catch (Exception ex)
                            {
                                HandleError(new InvalidOperationException(LocalizedStrings.Str2299Params
                                                                          .Put(series.Arg, emptyDate, security.Security.Id), ex));
                            }
                        }
                    }
                }
                #endregion
            }

            if (CanProcess())
            {
                this.AddInfoLog(LocalizedStrings.Str2300);
            }

            return(base.OnProcess());
        }
Example #11
0
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            if (_connectors.Count > 0)
            {
                foreach (var connector in _connectors.Cache)
                {
                    connector.Start();
                }

                return;
            }

            if (HistoryPath.Folder.IsEmpty() || !Directory.Exists(HistoryPath.Folder))
            {
                MessageBox.Show(this, LocalizedStrings.Str3014);
                return;
            }

            if (_connectors.Any(t => t.State != EmulationStates.Stopped))
            {
                MessageBox.Show(this, LocalizedStrings.Str3015);
                return;
            }

            var id = SecId.Text.ToSecurityId();

            //if (secIdParts.Length != 2)
            //{
            //	MessageBox.Show(this, LocalizedStrings.Str3016);
            //	return;
            //}

            var timeFrame = TimeSpan.FromMinutes(TimeFrame.SelectedIndex == 0 ? 1 : 5);

            var secCode = id.SecurityCode;
            var board   = _exchangeInfoProvider.GetOrCreateBoard(id.BoardCode);

            // create test security
            var security = new Security
            {
                Id    = SecId.Text,              // sec id has the same name as folder with historical data
                Code  = secCode,
                Board = board,
            };

            // create backtesting modes
            var settings = new[]
            {
                Tuple.Create(
                    TicksCheckBox,
                    TicksProgress,
                    TicksParameterGrid,
                    // ticks
                    new EmulationInfo
                {
                    UseTicks     = true,
                    CurveColor   = Colors.DarkGreen,
                    StrategyName = LocalizedStrings.Ticks
                },
                    TicksChart,
                    TicksEquity,
                    TicksPosition),

                Tuple.Create(
                    TicksAndDepthsCheckBox,
                    TicksAndDepthsProgress,
                    TicksAndDepthsParameterGrid,
                    // ticks + order book
                    new EmulationInfo
                {
                    UseTicks       = true,
                    UseMarketDepth = true,
                    CurveColor     = Colors.Red,
                    StrategyName   = LocalizedStrings.XamlStr757
                },
                    TicksAndDepthsChart,
                    TicksAndDepthsEquity,
                    TicksAndDepthsPosition),

                Tuple.Create(
                    DepthsCheckBox,
                    DepthsProgress,
                    DepthsParameterGrid,
                    // order book
                    new EmulationInfo
                {
                    UseMarketDepth = true,
                    CurveColor     = Colors.OrangeRed,
                    StrategyName   = LocalizedStrings.MarketDepths
                },
                    DepthsChart,
                    DepthsEquity,
                    DepthsPosition),

                Tuple.Create(
                    CandlesCheckBox,
                    CandlesProgress,
                    CandlesParameterGrid,
                    // candles
                    new EmulationInfo
                {
                    UseCandleTimeFrame = timeFrame,
                    CurveColor         = Colors.DarkBlue,
                    StrategyName       = LocalizedStrings.Candles
                },
                    CandlesChart,
                    CandlesEquity,
                    CandlesPosition),

                Tuple.Create(
                    CandlesAndDepthsCheckBox,
                    CandlesAndDepthsProgress,
                    CandlesAndDepthsParameterGrid,
                    // candles + orderbook
                    new EmulationInfo
                {
                    UseMarketDepth     = true,
                    UseCandleTimeFrame = timeFrame,
                    CurveColor         = Colors.Cyan,
                    StrategyName       = LocalizedStrings.XamlStr635
                },
                    CandlesAndDepthsChart,
                    CandlesAndDepthsEquity,
                    CandlesAndDepthsPosition),

                Tuple.Create(
                    OrderLogCheckBox,
                    OrderLogProgress,
                    OrderLogParameterGrid,
                    // order log
                    new EmulationInfo
                {
                    UseOrderLog  = true,
                    CurveColor   = Colors.CornflowerBlue,
                    StrategyName = LocalizedStrings.OrderLog
                },
                    OrderLogChart,
                    OrderLogEquity,
                    OrderLogPosition),

                Tuple.Create(
                    Level1CheckBox,
                    Level1Progress,
                    Level1ParameterGrid,
                    // order log
                    new EmulationInfo
                {
                    UseLevel1    = true,
                    CurveColor   = Colors.Aquamarine,
                    StrategyName = LocalizedStrings.Level1
                },
                    Level1Chart,
                    Level1Equity,
                    Level1Position),

                Tuple.Create(
                    FinamCandlesCheckBox,
                    FinamCandlesProgress,
                    FinamCandlesParameterGrid,
                    // candles
                    new EmulationInfo
                {
                    UseCandleTimeFrame   = timeFrame,
                    CustomHistoryAdapter = g => new FinamMessageAdapter(g),
                    CurveColor           = Colors.DarkBlue,
                    StrategyName         = LocalizedStrings.FinamCandles
                },
                    FinamCandlesChart,
                    FinamCandlesEquity,
                    FinamCandlesPosition),

                Tuple.Create(
                    YahooCandlesCheckBox,
                    YahooCandlesProgress,
                    YahooCandlesParameterGrid,
                    // candles
                    new EmulationInfo
                {
                    UseCandleTimeFrame   = timeFrame,
                    CustomHistoryAdapter = g => new YahooMessageAdapter(g),
                    CurveColor           = Colors.DarkBlue,
                    StrategyName         = LocalizedStrings.YahooCandles
                },
                    YahooCandlesChart,
                    YahooCandlesEquity,
                    YahooCandlesPosition),

                Tuple.Create(
                    RandomCheckBox,
                    RandomProgress,
                    RandomParameterGrid,
                    // candles
                    new EmulationInfo
                {
                    UseCandleTimeFrame   = timeFrame,
                    CustomHistoryAdapter = g => new OwnMessageAdapter(g),
                    CurveColor           = Colors.DarkBlue,
                    StrategyName         = LocalizedStrings.Custom
                },
                    RandomChart,
                    RandomEquity,
                    RandomPosition),
            };

            // storage to historical data
            var storageRegistry = new StorageRegistry
            {
                // set historical path
                DefaultDrive = new LocalMarketDataDrive(HistoryPath.Folder)
            };

            var startTime = ((DateTime)From.EditValue).UtcKind();
            var stopTime  = ((DateTime)To.EditValue).UtcKind();

            // (ru only) ОЛ необходимо загружать с 18.45 пред дня, чтобы стаканы строились правильно
            if (OrderLogCheckBox.IsChecked == true)
            {
                startTime = startTime.Subtract(TimeSpan.FromDays(1)).AddHours(18).AddMinutes(45).AddTicks(1).ApplyMoscow().UtcDateTime;
            }

            // set ProgressBar bounds
            _progressBars.ForEach(p =>
            {
                p.Value   = 0;
                p.Maximum = 100;
            });

            var logManager      = new LogManager();
            var fileLogListener = new FileLogListener("sample.log");

            logManager.Listeners.Add(fileLogListener);
            //logManager.Listeners.Add(new DebugLogListener());	// for track logs in output window in Vusial Studio (poor performance).

            var generateDepths = GenDepthsCheckBox.IsChecked == true;
            var maxDepth       = MaxDepth.Text.To <int>();
            var maxVolume      = MaxVolume.Text.To <int>();
            var secId          = security.ToSecurityId();

            SetIsEnabled(false, false, false);

            foreach (var set in settings)
            {
                if (set.Item1.IsChecked == false)
                {
                    continue;
                }

                var title = (string)set.Item1.Content;

                InitChart(set.Item5, set.Item6, set.Item7);

                var progressBar   = set.Item2;
                var statistic     = set.Item3;
                var emulationInfo = set.Item4;

                var level1Info = new Level1ChangeMessage
                {
                    SecurityId = secId,
                    ServerTime = startTime,
                }
                .TryAdd(Level1Fields.PriceStep, secCode == "RIZ2" ? 10m : 0.05m)
                .TryAdd(Level1Fields.StepPrice, 6m)
                .TryAdd(Level1Fields.MinPrice, 10m)
                .TryAdd(Level1Fields.MaxPrice, 1000000m)
                .TryAdd(Level1Fields.MarginBuy, 10000m)
                .TryAdd(Level1Fields.MarginSell, 10000m);

                // test portfolio
                var portfolio = Portfolio.CreateSimulator();

                var secProvider = (ISecurityProvider) new CollectionSecurityProvider(new[] { security });

                // create backtesting connector
                var connector = new HistoryEmulationConnector(
                    secProvider, new[] { portfolio })
                {
                    EmulationAdapter =
                    {
                        Settings         =
                        {
                            // match order if historical price touched our limit order price.
                            // It is terned off, and price should go through limit order price level
                            // (more "severe" test mode)
                            MatchOnTouch = false,
                        }
                    },

                    //UseExternalCandleSource = emulationInfo.UseCandleTimeFrame != null,

                    //CreateDepthFromOrdersLog = emulationInfo.UseOrderLog,
                    //CreateTradesFromOrdersLog = emulationInfo.UseOrderLog,

                    HistoryMessageAdapter =
                    {
                        StorageRegistry             = storageRegistry,

                        OrderLogMarketDepthBuilders =
                        {
                            {
                                secId,
                                new OrderLogMarketDepthBuilder(secId)
                            }
                        }
                    },

                    // set market time freq as time frame
                    MarketTimeChangedInterval = timeFrame,
                };

                ((ILogSource)connector).LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info;

                logManager.Sources.Add(connector);

                var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame)
                {
                    BuildCandlesMode  = emulationInfo.UseCandleTimeFrame == null ? MarketDataBuildModes.Build : MarketDataBuildModes.Load,
                    BuildCandlesFrom2 = emulationInfo.UseOrderLog ? DataType.OrderLog : null,
                };

                _shortMa = new SimpleMovingAverage {
                    Length = 10
                };
                _shortElem = new ChartIndicatorElement
                {
                    Color          = Colors.Coral,
                    ShowAxisMarker = false,
                    FullTitle      = _shortMa.ToString()
                };

                var chart = set.Item5;

                chart.AddElement(_area, _shortElem);

                _longMa = new SimpleMovingAverage {
                    Length = 80
                };
                _longElem = new ChartIndicatorElement
                {
                    ShowAxisMarker = false,
                    FullTitle      = _longMa.ToString()
                };
                chart.AddElement(_area, _longElem);

                // create strategy based on 80 5-min и 10 5-min
                var strategy = new SmaStrategy(series, _longMa, _shortMa, chart, _candlesElem, _tradesElem, _longElem, _shortElem)
                {
                    Volume    = 1,
                    Portfolio = portfolio,
                    Security  = security,
                    Connector = connector,
                    LogLevel  = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info,

                    // by default interval is 1 min,
                    // it is excessively for time range with several months
                    UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>()
                };

                logManager.Sources.Add(strategy);

                if (emulationInfo.CustomHistoryAdapter != null)
                {
                    connector.Adapter.InnerAdapters.Remove(connector.MarketDataAdapter);
                    connector.Adapter.InnerAdapters.Add(new EmulationMessageAdapter(emulationInfo.CustomHistoryAdapter(connector.TransactionIdGenerator), new InMemoryMessageChannel(new MessageByLocalTimeQueue(), "History out", err => err.LogError()), true, connector.EmulationAdapter.Emulator.SecurityProvider, connector.EmulationAdapter.Emulator.PortfolioProvider));
                }

                // set history range
                connector.HistoryMessageAdapter.StartDate = startTime;
                connector.HistoryMessageAdapter.StopDate  = stopTime;

                connector.NewSecurity += s =>
                {
                    if (s != security)
                    {
                        return;
                    }

                    // fill level1 values
                    connector.EmulationAdapter.SendInMessage(level1Info);

                    if (emulationInfo.UseMarketDepth)
                    {
                        connector.SubscribeMarketDepth(security);

                        if (
                            // if order book will be generated
                            generateDepths ||
                            // or backtesting will be on candles
                            emulationInfo.UseCandleTimeFrame != TimeSpan.Zero
                            )
                        {
                            // if no have order book historical data, but strategy is required,
                            // use generator based on last prices
                            connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security))
                            {
                                Interval           = TimeSpan.FromSeconds(1),                       // order book freq refresh is 1 sec
                                MaxAsksDepth       = maxDepth,
                                MaxBidsDepth       = maxDepth,
                                UseTradeVolume     = true,
                                MaxVolume          = maxVolume,
                                MinSpreadStepCount = 2,                                 // min spread generation is 2 pips
                                MaxSpreadStepCount = 5,                                 // max spread generation size (prevent extremely size)
                                MaxPriceStepCount  = 3                                  // pips size,
                            });
                        }
                    }

                    if (emulationInfo.UseOrderLog)
                    {
                        connector.SubscribeOrderLog(security);
                    }

                    if (emulationInfo.UseTicks)
                    {
                        connector.SubscribeTrades(security);
                    }

                    if (emulationInfo.UseLevel1)
                    {
                        connector.SubscribeLevel1(security);
                    }

                    // start strategy before emulation started
                    strategy.Start();

                    // start historical data loading when connection established successfully and all data subscribed
                    connector.Start();
                };

                // fill parameters panel
                statistic.Parameters.Clear();
                statistic.Parameters.AddRange(strategy.StatisticManager.Parameters);

                var equity = set.Item6;

                var pnlCurve           = equity.CreateCurve(LocalizedStrings.PnL + " " + emulationInfo.StrategyName, Colors.Green, Colors.Red, ChartIndicatorDrawStyles.Area);
                var unrealizedPnLCurve = equity.CreateCurve(LocalizedStrings.PnLUnreal + " " + emulationInfo.StrategyName, Colors.Black, ChartIndicatorDrawStyles.Line);
                var commissionCurve    = equity.CreateCurve(LocalizedStrings.Str159 + " " + emulationInfo.StrategyName, Colors.Red, ChartIndicatorDrawStyles.DashedLine);

                strategy.PnLChanged += () =>
                {
                    var data = new ChartDrawData();

                    data
                    .Group(strategy.CurrentTime)
                    .Add(pnlCurve, strategy.PnL - strategy.Commission ?? 0)
                    .Add(unrealizedPnLCurve, strategy.PnLManager.UnrealizedPnL ?? 0)
                    .Add(commissionCurve, strategy.Commission ?? 0);

                    equity.Draw(data);
                };

                var posItems = set.Item7.CreateCurve(emulationInfo.StrategyName, emulationInfo.CurveColor, ChartIndicatorDrawStyles.Line);

                strategy.PositionChanged += () =>
                {
                    var data = new ChartDrawData();

                    data
                    .Group(strategy.CurrentTime)
                    .Add(posItems, strategy.Position);

                    set.Item7.Draw(data);
                };

                connector.ProgressChanged += steps => this.GuiAsync(() => progressBar.Value = steps);

                connector.StateChanged += () =>
                {
                    if (connector.State == EmulationStates.Stopped)
                    {
                        strategy.Stop();

                        SetIsChartEnabled(chart, false);

                        if (_connectors.All(c => c.State == EmulationStates.Stopped))
                        {
                            logManager.Dispose();
                            _connectors.Clear();

                            SetIsEnabled(true, false, false);
                        }

                        this.GuiAsync(() =>
                        {
                            if (connector.IsFinished)
                            {
                                progressBar.Value = progressBar.Maximum;
                                MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime), title);
                            }
                            else
                            {
                                MessageBox.Show(this, LocalizedStrings.cancelled, title);
                            }
                        });
                    }
                    else if (connector.State == EmulationStates.Started)
                    {
                        if (_connectors.All(c => c.State == EmulationStates.Started))
                        {
                            SetIsEnabled(false, true, true);
                        }

                        SetIsChartEnabled(chart, true);
                    }
                    else if (connector.State == EmulationStates.Suspended)
                    {
                        if (_connectors.All(c => c.State == EmulationStates.Suspended))
                        {
                            SetIsEnabled(true, false, true);
                        }
                    }
                };

                if (ShowDepth.IsChecked == true)
                {
                    MarketDepth.UpdateFormat(security);

                    connector.NewMessage += message =>
                    {
                        if (message is QuoteChangeMessage quoteMsg)
                        {
                            MarketDepth.UpdateDepth(quoteMsg);
                        }
                    };
                }

                _connectors.Add(connector);

                progressBar.Value = 0;
            }

            _startEmulationTime = DateTime.Now;

            // start emulation
            foreach (var connector in _connectors.Cache)
            {
                // raise NewSecurities and NewPortfolio for full fill strategy properties
                connector.Connect();

                // 1 cent commission for trade
                connector.SendInMessage(new CommissionRuleMessage
                {
                    Rule = new CommissionPerTradeRule {
                        Value = 0.01m
                    }
                });
            }

            TabControl.Items.Cast <TabItem>().First(i => i.Visibility == Visibility.Visible).IsSelected = true;
        }
Example #12
0
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            if (HistoryPath.Folder.IsEmpty() || !Directory.Exists(HistoryPath.Folder))
            {
                MessageBox.Show(this, LocalizedStrings.Str3014);
                return;
            }

            if (Math.Abs(TestingProcess.Value - 0) > double.Epsilon)
            {
                MessageBox.Show(this, LocalizedStrings.Str3015);
                return;
            }

            var logManager      = new LogManager();
            var fileLogListener = new FileLogListener("sample.log");

            logManager.Listeners.Add(fileLogListener);

            // SMA periods
            var periods = new[]
            {
                new Tuple <int, int, Color>(80, 10, Colors.DarkGreen),
                new Tuple <int, int, Color>(70, 8, Colors.Red),
                new Tuple <int, int, Color>(60, 6, Colors.DarkBlue)
            };

            // storage to historical data
            var storageRegistry = new StorageRegistry
            {
                // set historical path
                DefaultDrive = new LocalMarketDataDrive(HistoryPath.Folder)
            };

            var timeFrame = TimeSpan.FromMinutes(5);

            // create test security
            var security = new Security
            {
                Id    = "RIZ2@FORTS",              // sec id has the same name as folder with historical data
                Code  = "RIZ2",
                Name  = "RTS-12.12",
                Board = ExchangeBoard.Forts,
            };

            var startTime = new DateTime(2012, 10, 1);
            var stopTime  = new DateTime(2012, 10, 31);

            var level1Info = new Level1ChangeMessage
            {
                SecurityId = security.ToSecurityId(),
                ServerTime = startTime,
            }
            .TryAdd(Level1Fields.PriceStep, 10m)
            .TryAdd(Level1Fields.StepPrice, 6m)
            .TryAdd(Level1Fields.MinPrice, 10m)
            .TryAdd(Level1Fields.MaxPrice, 1000000m)
            .TryAdd(Level1Fields.MarginBuy, 10000m)
            .TryAdd(Level1Fields.MarginSell, 10000m);

            // test portfolio
            var portfolio = new Portfolio
            {
                Name       = "test account",
                BeginValue = 1000000,
            };

            // create backtesting connector
            var batchEmulation = new BatchEmulation(new[] { security }, new[] { portfolio }, storageRegistry)
            {
                EmulationSettings =
                {
                    MarketTimeChangedInterval = timeFrame,
                    StartTime = startTime,
                    StopTime  = stopTime,

                    // count of parallel testing strategies
                    BatchSize                 = periods.Length,
                }
            };

            // handle historical time for update ProgressBar
            batchEmulation.ProgressChanged += (curr, total) => this.GuiAsync(() => TestingProcess.Value = total);

            batchEmulation.StateChanged += (oldState, newState) =>
            {
                if (batchEmulation.State != EmulationStates.Stopped)
                {
                    return;
                }

                this.GuiAsync(() =>
                {
                    if (batchEmulation.IsFinished)
                    {
                        TestingProcess.Value = TestingProcess.Maximum;
                        MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime));
                    }
                    else
                    {
                        MessageBox.Show(this, LocalizedStrings.cancelled);
                    }
                });
            };

            // get emulation connector
            var connector = batchEmulation.EmulationConnector;

            logManager.Sources.Add(connector);

            connector.NewSecurities += securities =>
            {
                if (securities.All(s => s != security))
                {
                    return;
                }

                // fill level1 values
                connector.SendInMessage(level1Info);

                connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security))
                {
                    // order book freq refresh is 1 sec
                    Interval = TimeSpan.FromSeconds(1),
                });
            };

            TestingProcess.Maximum = 100;
            TestingProcess.Value   = 0;

            _startEmulationTime = DateTime.Now;

            var strategies = periods
                             .Select(period =>
            {
                var candleManager = new CandleManager(connector);
                var series        = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);

                // create strategy based SMA
                var strategy = new SmaStrategy(candleManager, series, new SimpleMovingAverage {
                    Length = period.Item1
                }, new SimpleMovingAverage {
                    Length = period.Item2
                })
                {
                    Volume    = 1,
                    Security  = security,
                    Portfolio = portfolio,
                    Connector = connector,

                    // by default interval is 1 min,
                    // it is excessively for time range with several months
                    UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>()
                };

                strategy.SetCandleManager(candleManager);

                var curveItems       = Curve.CreateCurve(LocalizedStrings.Str3026Params.Put(period.Item1, period.Item2), period.Item3);
                strategy.PnLChanged += () =>
                {
                    var data = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.PnL,
                    };

                    this.GuiAsync(() => curveItems.Add(data));
                };

                Stat.AddStrategies(new[] { strategy });

                return(strategy);
            })
                             .ToEx(periods.Length);

            // start emulation
            batchEmulation.Start(strategies);
        }
Example #13
0
        private void StartEmulation()
        {
            if (_connector != null && _connector.State != EmulationStates.Stopped)
            {
                throw new InvalidOperationException(LocalizedStrings.Str3015);
            }

            if (Strategy == null)
            {
                throw new InvalidOperationException("Strategy not selected.");
            }

            var strategy = (EmulationDiagramStrategy)Strategy;

            if (strategy.DataPath.IsEmpty() || !Directory.Exists(strategy.DataPath))
            {
                throw new InvalidOperationException(LocalizedStrings.Str3014);
            }

            strategy
            .Composition
            .Parameters
            .ForEach(p =>
            {
                if (p.Type == typeof(Security) && p.Value == null)
                {
                    throw new InvalidOperationException(LocalizedStrings.Str1380);
                }
            });

            strategy.Reset();
            Reset();

            var securityId = "empty@empty";
            var secGen     = new SecurityIdGenerator();
            var secIdParts = secGen.Split(securityId);
            var secCode    = secIdParts.SecurityCode;
            var board      = ExchangeBoard.GetOrCreateBoard(secIdParts.BoardCode);
            var timeFrame  = strategy.CandlesTimeFrame;
            var useCandles = strategy.MarketDataSource == MarketDataSource.Candles;

            // create test security
            var security = new Security
            {
                Id    = securityId,              // sec id has the same name as folder with historical data
                Code  = secCode,
                Board = board,
            };

            // storage to historical data
            var storageRegistry = new StorageRegistry
            {
                // set historical path
                DefaultDrive = new LocalMarketDataDrive(strategy.DataPath)
            };

            var startTime = strategy.StartDate.ChangeKind(DateTimeKind.Utc);
            var stopTime  = strategy.StopDate.ChangeKind(DateTimeKind.Utc);

            // ProgressBar refresh step
            var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>();

            // set ProgressBar bounds
            TicksAndDepthsProgress.Value   = 0;
            TicksAndDepthsProgress.Maximum = 100;

            // test portfolio
            var portfolio = new Portfolio
            {
                Name       = "test account",
                BeginValue = 1000000,
            };

            var securityProvider = ConfigManager.GetService <ISecurityProvider>();

            // create backtesting connector
            _connector = new HistoryEmulationConnector(securityProvider, new[] { portfolio }, new StorageRegistry())
            {
                EmulationAdapter =
                {
                    Emulator                          =
                    {
                        Settings                      =
                        {
                            // match order if historical price touched our limit order price.
                            // It is terned off, and price should go through limit order price level
                            // (more "severe" test mode)
                            MatchOnTouch              = strategy.MatchOnTouch,
                            IsSupportAtomicReRegister = strategy.IsSupportAtomicReRegister,
                            Latency                   = strategy.EmulatoinLatency,
                        }
                    }
                },

                UseExternalCandleSource = useCandles,

                HistoryMessageAdapter =
                {
                    StorageRegistry = storageRegistry,

                    // set history range
                    StartDate = startTime,
                    StopDate  = stopTime,
                },

                // set market time freq as time frame
                MarketTimeChangedInterval = timeFrame,
            };

            ((ILogSource)_connector).LogLevel = strategy.DebugLog ? LogLevels.Debug : LogLevels.Info;

            ConfigManager.GetService <LogManager>().Sources.Add(_connector);

            strategy.Volume    = 1;
            strategy.Portfolio = portfolio;
            strategy.Security  = security;
            strategy.Connector = _connector;
            strategy.LogLevel  = strategy.DebugLog ? LogLevels.Debug : LogLevels.Info;

            // by default interval is 1 min,
            // it is excessively for time range with several months
            strategy.UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>();

            strategy.SetCandleManager(new CandleManager(_connector));

            _connector.NewSecurity += s =>
            {
                //TODO send real level1 message
                var level1Info = new Level1ChangeMessage
                {
                    SecurityId = s.ToSecurityId(),
                    ServerTime = startTime,
                }
                .TryAdd(Level1Fields.PriceStep, secIdParts.SecurityCode == "RIZ2" ? 10m : 1)
                .TryAdd(Level1Fields.StepPrice, 6m)
                .TryAdd(Level1Fields.MinPrice, 10m)
                .TryAdd(Level1Fields.MaxPrice, 1000000m)
                .TryAdd(Level1Fields.MarginBuy, 10000m)
                .TryAdd(Level1Fields.MarginSell, 10000m);

                // fill level1 values
                _connector.SendInMessage(level1Info);

                if (strategy.UseMarketDepths)
                {
                    _connector.RegisterMarketDepth(security);

                    if (
                        // if order book will be generated
                        strategy.GenerateDepths ||
                        // of backtesting will be on candles
                        useCandles
                        )
                    {
                        // if no have order book historical data, but strategy is required,
                        // use generator based on last prices
                        _connector.RegisterMarketDepth(new TrendMarketDepthGenerator(_connector.GetSecurityId(s))
                        {
                            Interval           = TimeSpan.FromSeconds(1),                   // order book freq refresh is 1 sec
                            MaxAsksDepth       = strategy.MaxDepths,
                            MaxBidsDepth       = strategy.MaxDepths,
                            UseTradeVolume     = true,
                            MaxVolume          = strategy.MaxVolume,
                            MinSpreadStepCount = 2,                             // min spread generation is 2 pips
                            MaxSpreadStepCount = 5,                             // max spread generation size (prevent extremely size)
                            MaxPriceStepCount  = 3                              // pips size,
                        });
                    }
                }
            };

            var nextTime = startTime + progressStep;

            // handle historical time for update ProgressBar
            _connector.MarketTimeChanged += d =>
            {
                if (_connector.CurrentTime < nextTime && _connector.CurrentTime < stopTime)
                {
                    return;
                }

                var steps = (_connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1;
                nextTime = startTime + (steps * progressStep.Ticks).To <TimeSpan>();
                this.GuiAsync(() => TicksAndDepthsProgress.Value = steps);
            };

            _connector.LookupSecuritiesResult += (ss) =>
            {
                if (strategy.ProcessState != ProcessStates.Stopped)
                {
                    return;
                }

                // start strategy before emulation started
                strategy.Start();

                // start historical data loading when connection established successfully and all data subscribed
                _connector.Start();
            };

            _connector.StateChanged += () =>
            {
                switch (_connector.State)
                {
                case EmulationStates.Stopped:
                    strategy.Stop();

                    this.GuiAsync(() =>
                    {
                        if (_connector.IsFinished)
                        {
                            TicksAndDepthsProgress.Value = TicksAndDepthsProgress.Maximum;
                        }
                    });
                    break;

                case EmulationStates.Started:
                    break;
                }
            };

            TicksAndDepthsProgress.Value = 0;

            DiagramDebuggerControl.Debugger.IsEnabled = true;

            // raise NewSecurities and NewPortfolio for full fill strategy properties
            _connector.Connect();

            // 1 cent commission for trade
            _connector.SendInMessage(new CommissionRuleMessage
            {
                Rule = new CommissionPerTradeRule
                {
                    Value = 0.01m
                }
            });
        }
Example #14
0
        protected override TimeSpan OnProcess()
        {
            var allSecurity = this.GetAllSecurity();

            var source = new GoogleHistorySource();

            var startDate = _settings.StartFrom;
            var endDate   = DateTime.Today - TimeSpan.FromDays(_settings.DayOffset);

            var allDates = startDate.Range(endDate, TimeSpan.FromDays(1)).ToArray();

            var hasSecurities = false;

            foreach (var security in GetWorkingSecurities())
            {
                hasSecurities = true;

                if (!CanProcess())
                {
                    break;
                }

                foreach (var pair in (allSecurity ?? security).GetCandleSeries())
                {
                    if (!CanProcess())
                    {
                        break;
                    }

                    if (pair.MessageType != typeof(TimeFrameCandleMessage))
                    {
                        this.AddWarningLog(LocalizedStrings.Str2296Params, pair);
                        continue;
                    }

                    var tf = (TimeSpan)pair.Arg;

                    var storage    = StorageRegistry.GetCandleMessageStorage(pair.MessageType, security.Security, tf, _settings.Drive, _settings.StorageFormat);
                    var emptyDates = allDates.Except(storage.Dates).ToArray();

                    if (emptyDates.IsEmpty())
                    {
                        this.AddInfoLog(LocalizedStrings.Str2297Params, tf, security.Security.Id);
                        continue;
                    }

                    var currDate = emptyDates.First();
                    var lastDate = emptyDates.Last();

                    while (currDate <= lastDate)
                    {
                        if (!CanProcess())
                        {
                            break;
                        }

                        if (_settings.IgnoreWeekends && !security.IsTradeDate(currDate))
                        {
                            this.AddDebugLog(LocalizedStrings.WeekEndDate, currDate);
                            currDate = currDate.AddDays(1);
                            continue;
                        }

                        try
                        {
                            var till = currDate + TimeSpan.FromDays(_settings.CandleDayStep).Max(tf);
                            this.AddInfoLog(LocalizedStrings.Str2298Params, tf, currDate, till, security.Security.Id);

                            var candles = source.GetCandles(security.Security, tf, currDate, till);

                            if (candles.Any())
                            {
                                SaveCandles(security, candles);
                            }
                            else
                            {
                                this.AddDebugLog(LocalizedStrings.NoData);
                            }
                        }
                        catch (Exception ex)
                        {
                            HandleError(new InvalidOperationException(LocalizedStrings.Str2299Params
                                                                      .Put(tf, currDate, security.Security.Id), ex));
                        }

                        currDate = currDate.AddDays(_settings.CandleDayStep);
                    }
                }
            }

            if (!hasSecurities)
            {
                this.AddWarningLog(LocalizedStrings.Str2292);
                return(TimeSpan.MaxValue);
            }

            if (CanProcess())
            {
                this.AddInfoLog(LocalizedStrings.Str2300);
            }

            return(base.OnProcess());
        }
Example #15
0
        private void LoadData(CandleSeries series)
        {
            var msgType = series.CandleType.ToCandleMessageType();

            _transactionId = _transactionIdGenerator.GetNextId();
            _holder.Clear();
            _holder.CreateCandleSeries(_transactionId, series);

            _candleTransform.Process(new ResetMessage());
            _candleBuilder = _builderProvider.Get(msgType);

            var storage = new StorageRegistry();

            //BusyIndicator.IsBusy = true;

            var path    = HistoryPath.Folder;
            var isBuild = BuildFromTicks.IsChecked == true;
            var format  = Format.SelectedFormat;

            var maxDays = (isBuild || series.CandleType != typeof(TimeFrameCandle))
                                ? 2
                                : 30 * (int)((TimeSpan)series.Arg).TotalMinutes;

            _mdMsg = series.ToMarketDataMessage(true);

            Task.Factory.StartNew(() =>
            {
                var date = DateTime.MinValue;

                if (isBuild)
                {
                    foreach (var tick in storage.GetTickMessageStorage(series.Security.ToSecurityId(), new LocalMarketDataDrive(path), format).Load())
                    {
                        _tradeGenerator.Process(tick);

                        if (_candleTransform.Process(tick))
                        {
                            var candles = _candleBuilder.Process(_mdMsg, _currCandle, _candleTransform);

                            foreach (var candle in candles)
                            {
                                _currCandle = candle;
                                _updatedCandles.Add((CandleMessage)candle.Clone());
                            }
                        }

                        _lastTime = tick.ServerTime;

                        if (date != tick.ServerTime.Date)
                        {
                            date = tick.ServerTime.Date;

                            //var str = date.To<string>();
                            //this.GuiAsync(() => BusyIndicator.BusyContent = str);

                            maxDays--;

                            if (maxDays == 0)
                            {
                                break;
                            }
                        }
                    }
                }
                else
                {
                    foreach (var candleMsg in storage.GetCandleMessageStorage(msgType, series.Security.ToSecurityId(), series.Arg, new LocalMarketDataDrive(path), format).Load())
                    {
                        if (candleMsg.State != CandleStates.Finished)
                        {
                            candleMsg.State = CandleStates.Finished;
                        }

                        _currCandle = candleMsg;
                        _updatedCandles.Add(candleMsg);

                        _lastTime = candleMsg.OpenTime;

                        if (candleMsg is TimeFrameCandleMessage)
                        {
                            _lastTime += (TimeSpan)series.Arg;
                        }

                        _tradeGenerator.Process(new ExecutionMessage
                        {
                            ExecutionType = ExecutionTypes.Tick,
                            SecurityId    = series.Security.ToSecurityId(),
                            ServerTime    = _lastTime,
                            TradePrice    = candleMsg.ClosePrice,
                        });

                        if (date != candleMsg.OpenTime.Date)
                        {
                            date = candleMsg.OpenTime.Date;

                            //var str = date.To<string>();
                            //this.GuiAsync(() => BusyIndicator.BusyContent = str);

                            maxDays--;

                            if (maxDays == 0)
                            {
                                break;
                            }
                        }
                    }
                }

                _historyLoaded = true;
            })
            .ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    Error(t.Exception.Message);
                }

                //BusyIndicator.IsBusy = false;
                Chart.IsAutoRange             = false;
                ModifyAnnotationBtn.IsEnabled = true;
                NewAnnotationBtn.IsEnabled    = true;
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
Example #16
0
		private void StartBtnClick(object sender, RoutedEventArgs e)
		{
			if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text))
			{
				MessageBox.Show(this, LocalizedStrings.Str3014);
				return;
			}

			if (Math.Abs(TestingProcess.Value - 0) > double.Epsilon)
			{
				MessageBox.Show(this, LocalizedStrings.Str3015);
				return;
			}

			var logManager = new LogManager();
			var fileLogListener = new FileLogListener("sample.log");
			logManager.Listeners.Add(fileLogListener);

			// SMA periods
			var periods = new[]
			{
				new Tuple<int, int, Color>(80, 10, Colors.DarkGreen),
				new Tuple<int, int, Color>(70, 8, Colors.Red),
				new Tuple<int, int, Color>(60, 6, Colors.DarkBlue)
			};

			// storage to historical data
			var storageRegistry = new StorageRegistry
			{
				// set historical path
				DefaultDrive = new LocalMarketDataDrive(HistoryPath.Text)
			};

			var timeFrame = TimeSpan.FromMinutes(5);

			// create test security
			var security = new Security
			{
				Id = "RIZ2@FORTS", // sec id has the same name as folder with historical data
				Code = "RIZ2",
				Name = "RTS-12.12",
				Board = ExchangeBoard.Forts,
			};

			var startTime = new DateTime(2012, 10, 1);
			var stopTime = new DateTime(2012, 10, 31);

			var level1Info = new Level1ChangeMessage
			{
				SecurityId = security.ToSecurityId(),
				ServerTime = startTime,
			}
			.TryAdd(Level1Fields.PriceStep, 10m)
			.TryAdd(Level1Fields.StepPrice, 6m)
			.TryAdd(Level1Fields.MinPrice, 10m)
			.TryAdd(Level1Fields.MaxPrice, 1000000m)
			.TryAdd(Level1Fields.MarginBuy, 10000m)
			.TryAdd(Level1Fields.MarginSell, 10000m);

			// test portfolio
			var portfolio = new Portfolio
			{
				Name = "test account",
				BeginValue = 1000000,
			};

			// create backtesting connector
			var batchEmulation = new BatchEmulation(new[] { security }, new[] { portfolio }, storageRegistry)
			{
				EmulationSettings =
				{
					MarketTimeChangedInterval = timeFrame,
					StartTime = startTime,
					StopTime = stopTime,

					// count of parallel testing strategies
					BatchSize = periods.Length,
				}
			};

			// handle historical time for update ProgressBar
			batchEmulation.ProgressChanged += (curr, total) => this.GuiAsync(() => TestingProcess.Value = total);

			batchEmulation.StateChanged += (oldState, newState) =>
			{
				if (batchEmulation.State != EmulationStates.Stopped)
					return;

				this.GuiAsync(() =>
				{
					if (batchEmulation.IsFinished)
					{
						TestingProcess.Value = TestingProcess.Maximum;
						MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime));
					}
					else
						MessageBox.Show(this, LocalizedStrings.cancelled);
				});
			};

			// получаем подключение для эмуляции
			var connector = batchEmulation.EmulationConnector;

			logManager.Sources.Add(connector);

			connector.NewSecurities += securities =>
			{
				if (securities.All(s => s != security))
					return;

				// fill level1 values
				connector.SendInMessage(level1Info);

				connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security))
				{
					// order book freq refresh is 1 sec
					Interval = TimeSpan.FromSeconds(1),
				});
			};

			TestingProcess.Maximum = 100;
			TestingProcess.Value = 0;

			_startEmulationTime = DateTime.Now;

			var strategies = periods
				.Select(period =>
				{
					var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);

					// create strategy based SMA
					var strategy = new SmaStrategy(series, new SimpleMovingAverage { Length = period.Item1 }, new SimpleMovingAverage { Length = period.Item2 })
					{
						Volume = 1,
						Security = security,
						Portfolio = portfolio,
						Connector = connector,

						// by default interval is 1 min,
						// it is excessively for time range with several months
						UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To<TimeSpan>()
					};

					strategy.SetCandleManager(new CandleManager(connector));

					var curveItems = Curve.CreateCurve(LocalizedStrings.Str3026Params.Put(period.Item1, period.Item2), period.Item3);
					strategy.PnLChanged += () =>
					{
						var data = new EquityData
						{
							Time = strategy.CurrentTime,
							Value = strategy.PnL,
						};

						this.GuiAsync(() => curveItems.Add(data));
					};

					Stat.AddStrategies(new[] { strategy });

					return strategy;
				})
				.ToEx(periods.Length);

			// start emulation
			batchEmulation.Start(strategies);
		}
Example #17
0
        private void OnOptimizeClick(object sender, RoutedEventArgs e)
        {
            btnOptimize.IsEnabled = false;
            _log.AddLog(new LogMessage(_log, DateTime.Now, LogLevels.Info, "Optimization is beginning.."));

            this.InitGrids();

            // создаем тестовый инструмент, на котором будет производится тестирование
            var security = new Security
            {
                Id = this.txtSecurityId.Text, // по идентификатору инструмента будет искаться папка с историческими маркет данными
                Code = this.txtSecurityCode.Text,
                Name = this.txtSecurityCode.Text,
                MinStepSize = 1,
                MinStepPrice = 1,
                ExchangeBoard = ExchangeBoard.Forts,
            };

            var storageRegistry = new StorageRegistry();
            ((LocalMarketDataDrive) storageRegistry.DefaultDrive).Path = this.txtHistoryPath.Text;
            ((LocalMarketDataDrive) storageRegistry.DefaultDrive).UseAlphabeticPath = true;

            var portfolio = new Portfolio { Name = "test account", BeginValue = 30000m };

            DateTime startTime;
            DateTime stopTime;

            if (!DateTime.TryParse(txtHistoryRangeEnd.Text, out stopTime))
            {
                stopTime = DateTime.Now;
                txtHistoryRangeEnd.Text = stopTime.ToString();
            }

            if (!DateTime.TryParse(txtHistoryRangeBegin.Text, out startTime))
            {
                startTime = stopTime.AddDays(-3);
                txtHistoryRangeBegin.Text = startTime.ToString();
            }

            Stopwatch sw = new Stopwatch();

            EMAStrategyOptimizer optimizer = new EMAStrategyOptimizer(security, storageRegistry, portfolio, startTime, stopTime)
                {
                    Volume = this.Volume,
                    Log = _log
                };

            optimizer.StateChanged += () =>
            {
                if (optimizer.State == OptimizationState.Finished)
                {
                    sw.Stop();

                    _log.AddLog(new LogMessage(_log, DateTime.Now, LogLevels.Info,
                                               String.Format("Opt done ({0}). The best startegy: PnL: {1}, {2}",
                                                             sw.Elapsed,
                                                             optimizer.BestResult.Value.PnLManager.PnL,
                                                             optimizer.BestResult.Key
                                                   )));

                    optimizer.BestResult.Value.Trader.Orders.ForEach(OnOrderRegistered);
                    OnNewTrades(optimizer.BestResult.Value.Trader.MyTrades);

                    this.GuiAsync(() =>
                    {
                        this.UpdateStrategyStat(optimizer.BestResult.Value);
                        this.InitChart(optimizer.BestResult.Value);

                        optimizer.BestResult.Value.CandleSeries.GetCandles<TimeFrameCandle>().ForEach(DrawCandleAndEma);
                        optimizer.BestResult.Value.Trader.MyTrades.ForEach(DrawTrade);

                        // Replace MainOptVarItem with optimized one
                        this.MainOptVarItem = optimizer.BestResult.Key;

                        btnOptimize.IsEnabled = true;
                    });
                }
            };

            sw.Start();
            optimizer.Optimize();
        }
Example #18
0
        private void OnStartClick(object sender, RoutedEventArgs e)
        {
            if (_strategy != null && _strategy.ProcessState != ProcessStates.Stopped)
            {
                _strategy.Stop();
                return;
            }

            if (this.Portfolios.SelectedPortfolio == null)
            {
                this.Portfolios.SelectedIndex = this.Portfolios.Items.Count - 1;
            }

            this.InitGrids();

            _candleManager = new CandleManager(_trader);

            // Добавление в источник свечек TimeFrameCandleBuilder источник данных в виде файлов гидры
            var storageRegistry = new StorageRegistry();
            ((LocalMarketDataDrive) storageRegistry.DefaultDrive).Path = this.txtHistoryPath.Text;
            ((LocalMarketDataDrive) storageRegistry.DefaultDrive).UseAlphabeticPath = true;

            var cbs = new TradeStorageCandleBuilderSource { StorageRegistry = storageRegistry };
            _candleManager.Sources.OfType<TimeFrameCandleBuilder>().Single().Sources.Add(cbs);

            // регистрируем наш тайм-фрейм
            var series = new CandleSeries(typeof(TimeFrameCandle), _security, this.MainOptVarItem.TimeFrame);

            _strategy = new EMAEventModelStrategy(series,
                new ExponentialMovingAverage { Length = this.MainOptVarItem.FilterOptPeriod},
                new ExponentialMovingAverage { Length = this.MainOptVarItem.LongOptPeriods },
                new ExponentialMovingAverage { Length = this.MainOptVarItem.ShortOptPeriods },
                this.MainOptVarItem.TakeProfitUnit, this.MainOptVarItem.StopLossUnit)
            {
                Volume = this.Volume,
                Security = _security,
                Portfolio = this.Portfolios.SelectedPortfolio,
                Trader = _trader,
                UseQuoting = true //_trader is QuikTrader // hack to turn quoting off for RealTimeEmulationTrader
            };

            DateTime startTime;
            if (!DateTime.TryParse(txtHistoryRangeBegin.Text, out startTime))
            {
                startTime = DateTime.Now.AddDays(-3);
                txtHistoryRangeBegin.Text = startTime.ToString();
            }

            this.InitChart(_strategy);
            _candleManager.Processing += (candleSeries, candle) =>
            {
                if (candle.State == CandleStates.Finished)
                {
                    this.GuiAsync(() => DrawCandleAndEma(candle));
                }
            };
            _candleManager.Start(series, startTime, DateTime.MaxValue);

            // Subscribe UI to all strategy actions
            _strategy.Trader.NewOrders += orders => orders.ForEach(OnOrderRegistered);
            _strategy.Trader.NewMyTrades += OnNewTrades;
            _strategy.Trader.NewMyTrades += trades => this.GuiAsync(() => trades.ForEach(DrawTrade));
            _strategy.PropertyChanged += (o, args) => this.GuiAsync(() => OnStrategyPropertyChanged(o, args));
            _strategy.ProcessStateChanged += strategy =>
            {
                if (strategy.ProcessState == ProcessStates.Started)
                {
                    this.Start.Content = "Stop";
                }
                else if (strategy.ProcessState == ProcessStates.Stopped)
                {
                    this.Start.Content = "Start";
                }
            };

            _logManager.Sources.Add(_strategy);

            // запускаем процесс получения стакана, необходимый для работы алгоритма котирования
            _strategy.Start();

            this.Start.Content = "Stop";
        }
Example #19
0
		private void LoadData(string path)
		{
			var storage = new StorageRegistry();

			var maxDays = 2;

			BusyIndicator.IsBusy = true;

			Task.Factory.StartNew(() =>
			{
				var date = DateTime.MinValue;

				foreach (var tick in storage.GetTickMessageStorage(_security, new LocalMarketDataDrive(path)).Load())
				{
					AppendTick(tick.ServerTime, tick.TradePrice.Value, tick.Volume.Value);
					_lastTime = tick.ServerTime;

					if (date != tick.ServerTime.Date)
					{
						date = tick.ServerTime.Date;

                        this.GuiAsync(() =>
						{
							BusyIndicator.BusyContent = date.ToString();
						});

						maxDays--;

						if (maxDays == 0)
							break;
					}
				}
			})
			.ContinueWith(t =>
			{
				if (t.Exception != null)
					Error(t.Exception.Message);

				BusyIndicator.IsBusy = false;
			}, TaskScheduler.FromCurrentSynchronizationContext());
		}
Example #20
0
		private void StartButtonOnClick(object sender, RoutedEventArgs e)
		{
			_logManager.Sources.Clear();
			_bufferedChart.ClearAreas();

			Curve.Clear();
			PositionCurve.Clear();

			if (HistoryPathTextBox.Text.IsEmpty() || !Directory.Exists(HistoryPathTextBox.Text))
			{
				MessageBox.Show("Wrong path.");
				return;
			}

			if (_connector != null && _connector.State != EmulationStates.Stopped)
			{
				MessageBox.Show("Already launched.");
				return;
			}

			if (Composition == null)
			{
				MessageBox.Show("No strategy selected.");
				return;
			}

			var secGen = new SecurityIdGenerator();
			var secIdParts = secGen.Split(SecusityTextBox.Text);
			var secCode = secIdParts.SecurityCode;
			var board = ExchangeBoard.GetOrCreateBoard(secIdParts.BoardCode);
			var timeFrame = (TimeSpan)TimeFrameComboBox.SelectedItem;
			var useCandles = (string)MarketDataTypeComboBox.SelectedItem != "Ticks";

			// create test security
			var security = new Security
			{
				Id = SecusityTextBox.Text, // sec id has the same name as folder with historical data
				Code = secCode,
				Board = board,
			};

			// storage to historical data
			var storageRegistry = new StorageRegistry
			{
				// set historical path
				DefaultDrive = new LocalMarketDataDrive(HistoryPathTextBox.Text)
			};

			var startTime = ((DateTime)FromDatePicker.Value).ChangeKind(DateTimeKind.Utc);
			var stopTime = ((DateTime)ToDatePicke.Value).ChangeKind(DateTimeKind.Utc);

			// ProgressBar refresh step
			var progressStep = ((stopTime - startTime).Ticks / 100).To<TimeSpan>();

			// set ProgressBar bounds
			TicksAndDepthsProgress.Value = 0;
			TicksAndDepthsProgress.Maximum = 100;

			var level1Info = new Level1ChangeMessage
			{
				SecurityId = security.ToSecurityId(),
				ServerTime = startTime,
			}
			.TryAdd(Level1Fields.PriceStep, secIdParts.SecurityCode == "RIZ2" ? 10m : 1)
			.TryAdd(Level1Fields.StepPrice, 6m)
			.TryAdd(Level1Fields.MinPrice, 10m)
			.TryAdd(Level1Fields.MaxPrice, 1000000m)
			.TryAdd(Level1Fields.MarginBuy, 10000m)
			.TryAdd(Level1Fields.MarginSell, 10000m);

			// test portfolio
			var portfolio = new Portfolio
			{
				Name = "test account",
				BeginValue = 1000000,
			};

			// create backtesting connector
			_connector = new HistoryEmulationConnector(
				new[] { security },
				new[] { portfolio })
			{
				EmulationAdapter =
				{
					Emulator =
					{
						Settings =
						{
							// match order if historical price touched our limit order price. 
							// It is terned off, and price should go through limit order price level
							// (more "severe" test mode)
							MatchOnTouch = false,
						}
					}
				},

				UseExternalCandleSource = useCandles,

				HistoryMessageAdapter =
				{
					StorageRegistry = storageRegistry,

					// set history range
					StartDate = startTime,
					StopDate = stopTime,
				},

				// set market time freq as time frame
				MarketTimeChangedInterval = timeFrame,
			};

			//((ILogSource)_connector).LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info;

			_logManager.Sources.Add(_connector);

			var candleManager = !useCandles
					? new CandleManager(new TradeCandleBuilderSourceEx(_connector))
					: new CandleManager(_connector);

			// create strategy based on 80 5-min и 10 5-min
			var strategy = new DiagramStrategy
			{
				Volume = 1,
				Portfolio = portfolio,
				Security = security,
				Connector = _connector,
				//LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info,

				Composition = Composition,

				// by default interval is 1 min,
				// it is excessively for time range with several months
				UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To<TimeSpan>()
			};

			strategy.SetChart(_bufferedChart);
			strategy.SetCandleManager(candleManager);

			_logManager.Sources.Add(strategy);

			strategy.OrderRegistering += OnStrategyOrderRegistering;
			strategy.OrderReRegistering += OnStrategyOrderReRegistering;
			strategy.OrderRegisterFailed += OnStrategyOrderRegisterFailed;
			
			strategy.StopOrderRegistering += OnStrategyOrderRegistering;
			strategy.StopOrderReRegistering += OnStrategyOrderReRegistering;
			strategy.StopOrderRegisterFailed += OnStrategyOrderRegisterFailed;

			strategy.NewMyTrades += OnStrategyNewMyTrade;

			var pnlCurve = Curve.CreateCurve(LocalizedStrings.PnL + " " + strategy.Name, Colors.DarkGreen, EquityCurveChartStyles.Area);
			var unrealizedPnLCurve = Curve.CreateCurve(LocalizedStrings.PnLUnreal + strategy.Name, Colors.Black);
			var commissionCurve = Curve.CreateCurve(LocalizedStrings.Str159 + " " + strategy.Name, Colors.Red, EquityCurveChartStyles.DashedLine);
			
			strategy.PnLChanged += () =>
			{
				var pnl = new EquityData
				{
					Time = strategy.CurrentTime,
					Value = strategy.PnL - strategy.Commission ?? 0
				};

				var unrealizedPnL = new EquityData
				{
					Time = strategy.CurrentTime,
					Value = strategy.PnLManager.UnrealizedPnL
				};

				var commission = new EquityData
				{
					Time = strategy.CurrentTime,
					Value = strategy.Commission ?? 0
				};

				pnlCurve.Add(pnl);
				unrealizedPnLCurve.Add(unrealizedPnL);
				commissionCurve.Add(commission);
			};

			var posItems = PositionCurve.CreateCurve(strategy.Name, Colors.DarkGreen);

			strategy.PositionChanged += () => posItems.Add(new EquityData { Time = strategy.CurrentTime, Value = strategy.Position });

			_connector.NewSecurities += securities =>
			{
				if (securities.All(s => s != security))
					return;

				// fill level1 values
				_connector.SendInMessage(level1Info);

				//_connector.RegisterMarketDepth(security);
				if (!useCandles)
					_connector.RegisterTrades(security);

				// start strategy before emulation started
				strategy.Start();

				// start historical data loading when connection established successfully and all data subscribed
				_connector.Start();
			};

			var nextTime = startTime + progressStep;

			// handle historical time for update ProgressBar
			_connector.MarketTimeChanged += d =>
			{
				if (_connector.CurrentTime < nextTime && _connector.CurrentTime < stopTime)
					return;

				var steps = (_connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1;
				nextTime = startTime + (steps * progressStep.Ticks).To<TimeSpan>();
				this.GuiAsync(() => TicksAndDepthsProgress.Value = steps);
			};

			_connector.StateChanged += () =>
			{
				switch (_connector.State)
				{
					case EmulationStates.Stopped:
						strategy.Stop();
						SetIsEnabled(false);

						this.GuiAsync(() =>
						{
							if (_connector.IsFinished)
							{
								TicksAndDepthsProgress.Value = TicksAndDepthsProgress.Maximum;
								MessageBox.Show("Done.");
							}
							else
								MessageBox.Show("Cancelled.");
						});
						break;
					case EmulationStates.Started:
						SetIsEnabled(true);
						break;
				}
			};

			TicksAndDepthsProgress.Value = 0;

			// raise NewSecurities and NewPortfolio for full fill strategy properties
			_connector.Connect();

			// 1 cent commission for trade
			_connector.SendInMessage(new CommissionRuleMessage
			{
				Rule = new CommissionPerTradeRule { Value = 0.01m }
			});
		}
Example #21
0
        private void Convert_OnClick(object sender, RoutedEventArgs e)
        {
            Convert.IsEnabled = false;

            if (_isStarted)
            {
                _logManager.Application.AddInfoLog("Остановка конвертации.");
                _isStarted = false;
                return;
            }

            QshFolder.IsEnabled = StockSharpFolder.IsEnabled = Format.IsEnabled = false;

            _logManager.Application.AddInfoLog("Запуск конвертации.");
            _isStarted = true;

            var settings = new Settings
            {
                QshFolder = QshFolder.Folder,
                StockSharpFolder = StockSharpFolder.Folder,
                Format = Format.GetSelectedValue<StorageFormats>() ?? StorageFormats.Binary
            };

            try
            {
                new XmlSerializer<Settings>().Serialize(settings, _settingsFile);
            }
            catch (Exception ex)
            {
                ex.LogError();
            }

            Task.Factory.StartNew(() =>
            {
                var registry = new StorageRegistry();
                ((LocalMarketDataDrive)registry.DefaultDrive).Path = settings.StockSharpFolder;

                this.GuiAsync(() =>
                {
                    Convert.Content = "Остановить";
                    Convert.IsEnabled = true;
                });

                ConvertDirectory(settings.QshFolder, registry, settings.Format, ExchangeBoard.Forts /* TODO надо сделать выбор в GUI */);
            })
            .ContinueWith(t =>
            {
                Convert.Content = "Запустить";
                Convert.IsEnabled = true;

                QshFolder.IsEnabled = StockSharpFolder.IsEnabled = Format.IsEnabled = true;

                if (t.IsFaulted)
                {
                    t.Exception.LogError();

                    new MessageBoxBuilder()
                        .Text("В процессе конвертации произошла ошибка. Ошибка записана в лог.")
                        .Error()
                        .Owner(this)
                        .Show();

                    return;
                }

                new MessageBoxBuilder()
                    .Text("Конвертация {0}.".Put(_isStarted ? "выполнена" : "остановлена"))
                    .Owner(this)
                    .Show();

            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
		private void LoadData()
		{
			_candle = null;
			_lastPrice = 0m;
			_allCandles.Clear();

			var id = new SecurityIdGenerator().Split(SecurityId.Text);

			_security = new Security
			{
				Id = SecurityId.Text,
				PriceStep = 5,
				Board = ExchangeBoard.GetBoard(id.BoardCode)
			};

			Chart.Reset(new IChartElement[] { _candleElement1 });

			var storage = new StorageRegistry();

			var maxDays = 2;

			BusyIndicator.IsBusy = true;

			var path = HistoryPath.Folder;

			Task.Factory.StartNew(() =>
			{
				var date = DateTime.MinValue;

				foreach (var tick in storage.GetTickMessageStorage(_security, new LocalMarketDataDrive(path)).Load())
				{
					AppendTick(_security, tick);
					_lastTime = tick.ServerTime;

					if (date != tick.ServerTime.Date)
					{
						date = tick.ServerTime.Date;

						this.GuiAsync(() =>
						{
							BusyIndicator.BusyContent = date.ToString();
						});

						maxDays--;

						if (maxDays == 0)
							break;
					}
				}
			})
			.ContinueWith(t =>
			{
				if (t.Exception != null)
					Error(t.Exception.Message);

				BusyIndicator.IsBusy = false;
			}, TaskScheduler.FromCurrentSynchronizationContext());
		}
		/// <summary>
		/// The method is called when the <see cref="Strategy.Start"/> method has been called and the <see cref="Strategy.ProcessState"/> state has been taken the <see cref="ProcessStates.Started"/> value.
		/// </summary>
		protected override void OnStarted()
		{
			var storateRegistry = new StorageRegistry();

			var drive = Environment.GetValue<IMarketDataDrive>("Drive");
			if (drive != null)
				storateRegistry.DefaultDrive = drive;

			StorateRegistry = storateRegistry;

			ThreadingHelper
				.Thread(() =>
				{
					try
					{
						OnAnalyze();
					}
					catch (Exception ex)
					{
						this.AddErrorLog(ex);
						ex.LogError();
					}
				})
				.Name("{0} analyze thread.".Put(Name))
				.Culture(CultureInfo.InvariantCulture)
				.Launch();
		}
Example #24
0
        protected override TimeSpan OnProcess()
        {
            var source = new TrueFXSource();

            if (_settings.UseTemporaryFiles != TempFiles.NotUse)
            {
                source.DumpFolder = GetTempPath();
            }

            var allSecurity = this.GetAllSecurity();

            // если фильтр по инструментам выключен (выбран инструмент все инструменты)
            IEnumerable <HydraTaskSecurity> selectedSecurities = (allSecurity != null
                                ? this.ToHydraSecurities(EntityRegistry.Securities.Filter(ExchangeBoard.TrueFX))
                                : Settings.Securities
                                                                  ).ToArray();

            if (selectedSecurities.IsEmpty())
            {
                this.AddWarningLog(LocalizedStrings.Str2289);

                source.Refresh(EntityRegistry.Securities, new Security(), SaveSecurity, () => !CanProcess(false));

                selectedSecurities = this.ToHydraSecurities(EntityRegistry.Securities.Filter(ExchangeBoard.TrueFX));
            }

            if (selectedSecurities.IsEmpty())
            {
                this.AddWarningLog(LocalizedStrings.Str2292);
                return(TimeSpan.MaxValue);
            }

            var startDate = _settings.StartFrom;
            var endDate   = DateTime.Today - TimeSpan.FromDays(_settings.DayOffset);

            var allDates = startDate.Range(endDate, TimeSpan.FromDays(1)).ToArray();

            foreach (var security in selectedSecurities)
            {
                if (!CanProcess())
                {
                    break;
                }

                if ((allSecurity ?? security).IsLevel1Enabled())
                {
                    var storage    = StorageRegistry.GetLevel1MessageStorage(security.Security, _settings.Drive, _settings.StorageFormat);
                    var emptyDates = allDates.Except(storage.Dates).ToArray();

                    if (emptyDates.IsEmpty())
                    {
                        this.AddInfoLog(LocalizedStrings.Str2293Params, security.Security.Id);
                    }
                    else
                    {
                        var secId = security.Security.ToSecurityId();

                        foreach (var emptyDate in emptyDates)
                        {
                            if (!CanProcess())
                            {
                                break;
                            }

                            try
                            {
                                this.AddInfoLog(LocalizedStrings.Str2294Params, emptyDate, security.Security.Id);
                                var ticks = source.LoadTickMessages(secId, emptyDate);

                                if (ticks.Any())
                                {
                                    SaveLevel1Changes(security, ticks);
                                }
                                else
                                {
                                    this.AddDebugLog(LocalizedStrings.NoData);
                                }

                                if (_settings.UseTemporaryFiles == TempFiles.UseAndDelete)
                                {
                                    File.Delete(source.GetDumpFile(security.Security, emptyDate, emptyDate, typeof(Level1ChangeMessage), null));
                                }
                            }
                            catch (Exception ex)
                            {
                                HandleError(new InvalidOperationException(LocalizedStrings.Str2295Params
                                                                          .Put(emptyDate, security.Security.Id), ex));
                            }
                        }
                    }
                }
                else
                {
                    this.AddDebugLog(LocalizedStrings.MarketDataNotEnabled, security.Security.Id, typeof(Level1ChangeMessage).Name);
                }

                if (!CanProcess())
                {
                    break;
                }
            }

            if (CanProcess())
            {
                this.AddInfoLog(LocalizedStrings.Str2300);
            }

            return(base.OnProcess());
        }