Example #1
0
		public PortfolioCommand(Portfolio portfolio, bool isNew)
		{
			if (portfolio == null)
				throw new ArgumentNullException("portfolio");

			Portfolio = portfolio;
			IsNew = isNew;
		}
        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()
		{
			try
			{
				Console.Write(LocalizedStrings.Str2992);
				var account1 = Console.ReadLine();

				Console.Write(LocalizedStrings.Str2993);
				var account2 = Console.ReadLine();

				using (var quikTrader1 = new QuikTrader { LuaFixServerAddress = "127.0.0.1:5001".To<EndPoint>() })
				using (var quikTrader2 = new QuikTrader { LuaFixServerAddress = "127.0.0.1:5002".To<EndPoint>() })
				{
					// подписываемся на событие ошибок обработки данных и разрыва соединения
					//
					quikTrader1.Error += OnError;
					quikTrader2.Error += OnError;

					quikTrader1.ConnectionError += OnError;
					quikTrader2.ConnectionError += OnError;

				
					var portfoliosWait = new ManualResetEvent(false);

					Action<IEnumerable<Portfolio>> newPortfolios = portfolios =>
					{
						if (_portfolio1 == null)
							_portfolio1 = portfolios.FirstOrDefault(p => p.Name == account1);

						if (_portfolio2 == null)
							_portfolio2 = portfolios.FirstOrDefault(p => p.Name == account2);

						// если оба инструмента появились
						if (_portfolio1 != null && _portfolio2 != null)
							portfoliosWait.Set();
					};

					// подписываемся на события новых портфелей
					quikTrader1.NewPortfolios += newPortfolios;
					quikTrader2.NewPortfolios += newPortfolios;


					var securitiesWait = new ManualResetEvent(false);

					// подписываемся на события новых инструментов
					quikTrader1.NewSecurities += securities =>
					{
						if (_lkoh == null)
							_lkoh = securities.FirstOrDefault(s => s.Code == "LKOH");

						// если оба инструмента появились
						if (_lkoh != null && _riz0 != null)
							securitiesWait.Set();
					};
					quikTrader2.NewSecurities += securities =>
					{
						if (_riz0 == null)
							_riz0 = securities.FirstOrDefault(s => s.Code == "RIZ0");

						// если оба инструмента появились
						if (_lkoh != null && _riz0 != null)
							securitiesWait.Set();
					};


					// запускаем экспорты в Quik-ах, когда получим событие об успешном соединении
					//
					quikTrader1.Connected += () =>
					{
						Console.WriteLine(LocalizedStrings.Str2994Params.Put(quikTrader1.LuaFixServerAddress));
					};
					quikTrader2.Connected += () =>
					{
						Console.WriteLine(LocalizedStrings.Str2994Params.Put(quikTrader2.LuaFixServerAddress));
					};

					// производим подключение каждого из QuikTrader-а
					//
					quikTrader1.Connect();
					quikTrader2.Connect();

					Console.WriteLine(LocalizedStrings.Str2995);
					portfoliosWait.WaitOne();
					securitiesWait.WaitOne();

					Console.WriteLine(LocalizedStrings.Str2996);
					if (_lkoh.BestBid == null || _riz0.BestBid == null)
						throw new Exception(LocalizedStrings.Str2990);

					quikTrader1.RegisterOrder(new Order
					{
						Portfolio = _portfolio1,
						Volume = 1,
						Security = _lkoh,
						Price = _lkoh.BestBid.Price
					});
					Console.WriteLine(LocalizedStrings.Str2997);

					quikTrader2.RegisterOrder(new Order
					{
						Portfolio = _portfolio2,
						Volume = 1,
						Security = _riz0,
						Price = _riz0.BestBid.Price
					});
					Console.WriteLine(LocalizedStrings.Str2998);
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
			}
		}
Example #4
0
			public override void LookupPortfolios(Portfolio criteria)
			{
				_realConnector.LookupPortfolios(criteria);
			}
		private void SendPortfolio(Portfolio portfolio)
		{
			SendInMessage(portfolio.ToMessage());

			var money = _initialMoney[portfolio];

			SendInMessage(
				EmulationAdapter
					.CreatePortfolioChangeMessage(portfolio.Name)
						.Add(PositionChangeTypes.BeginValue, money)
						.Add(PositionChangeTypes.CurrentValue, money)
						.Add(PositionChangeTypes.BlockedValue, 0m));
		}
Example #6
0
		/// <summary>
		/// Создать копию объекта <see cref="Portfolio"/>.
		/// </summary>
		/// <returns>Копия объекта.</returns>
		public Portfolio Clone()
		{
			var clone = new Portfolio();
			CopyTo(clone);
			return clone;
		}
Example #7
0
		/// <summary>
		/// Отменить группу заявок на бирже по фильтру.
		/// </summary>
		/// <param name="transactionId">Идентификатор транзакции отмены.</param>
		/// <param name="isStopOrder"><see langword="true"/>, если нужно отменить только стоп-заявки, false - если только обычный и null - если оба типа.</param>
		/// <param name="portfolio">Портфель. Если значение равно null, то портфель не попадает в фильтр снятия заявок.</param>
		/// <param name="direction">Направление заявки. Если значение равно null, то направление не попадает в фильтр снятия заявок.</param>
		/// <param name="board">Торговая площадка. Если значение равно null, то площадка не попадает в фильтр снятия заявок.</param>
		/// <param name="security">Инструмент. Если значение равно null, то инструмент не попадает в фильтр снятия заявок.</param>
		protected override void OnCancelOrders(long transactionId, bool? isStopOrder = null, Portfolio portfolio = null, Sides? direction = null, ExchangeBoard board = null, Security security = null)
		{
			if (Version == SmartComVersions.V2 && isStopOrder == null && portfolio == null && direction == null && board == null && security == null)
				base.OnCancelOrders(transactionId);
			else
				this.CancelOrders(Orders, isStopOrder, portfolio, direction, board, security);
		}
		private void Button_Click(object sender, RoutedEventArgs e)
		{
			var wnd = new PortfolioPickerWindow();

			if (Portfolios != null)
				wnd.Portfolios = Portfolios;

			if (wnd.ShowModal(this))
			{
				SelectedPortfolio = wnd.SelectedPortfolio;
			}
		}
Example #9
0
		/// <summary>
		/// Отменить группу заявок на бирже по фильтру.
		/// </summary>
		/// <param name="transactionId">Идентификатор транзакции отмены.</param>
		/// <param name="isStopOrder"><see langword="true"/>, если нужно отменить только стоп-заявки, <see langword="false"/> - если только обычный и <see langword="null"/> - если оба типа.</param>
		/// <param name="portfolio">Портфель. Если значение равно <see langword="null"/>, то портфель не попадает в фильтр снятия заявок.</param>
		/// <param name="direction">Направление заявки. Если значение равно <see langword="null"/>, то направление не попадает в фильтр снятия заявок.</param>
		/// <param name="board">Торговая площадка. Если значение равно <see langword="null"/>, то площадка не попадает в фильтр снятия заявок.</param>
		/// <param name="security">Инструмент. Если значение равно <see langword="null"/>, то инструмент не попадает в фильтр снятия заявок.</param>
		protected override void OnCancelOrders(long transactionId, bool? isStopOrder = null, Portfolio portfolio = null, Sides? direction = null, ExchangeBoard board = null, Security security = null)
		{
			if (security != null && portfolio != null && security.Type == SecurityTypes.Future && !security.UnderlyingSecurityId.IsEmpty())
				base.OnCancelOrders(transactionId, isStopOrder, portfolio, direction, board, security);
			else
				this.CancelOrders(Orders, isStopOrder, portfolio, direction, board);
		}
Example #10
0
		private void ChangePosition(Security security, Portfolio portfolio, decimal diff)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			if (portfolio == null)
				throw new ArgumentNullException("portfolio");

			bool isNew;
			var position = _positions.SafeAdd(Tuple.Create(security, portfolio),
			    key => new Position { Security = key.Item1, Portfolio = key.Item2 }, out isNew);

			position.CurrentValue += diff;

			if (isNew)
				NewPosition.SafeInvoke(position);
			else
				PositionChanged.SafeInvoke(position);
		}
		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;
			var settings = strategy.EmulationSettings;

			if (settings.MarketDataSettings == null)
				throw new InvalidOperationException(LocalizedStrings.Str3014);

			new SetDefaultEmulationSettingsCommand(settings).Process(this);

			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 = settings.CandlesTimeFrame;
			var useCandles = settings.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 StudioStorageRegistry
			{
				MarketDataSettings = settings.MarketDataSettings
			};

			var startTime = settings.StartDate.ChangeKind(DateTimeKind.Utc);
			var stopTime = settings.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 = settings.MatchOnTouch, 
							IsSupportAtomicReRegister = settings.IsSupportAtomicReRegister,
							Latency = settings.EmulatoinLatency,
						}
					}
				},

				UseExternalCandleSource = useCandles,

				HistoryMessageAdapter =
				{
					StorageRegistry = storageRegistry,
					StorageFormat = settings.StorageFormat,

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

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

			((ILogSource)_connector).LogLevel = settings.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 = settings.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 (settings.UseMarketDepths)
				{
					_connector.RegisterMarketDepth(security);

					if (
							// if order book will be generated
							settings.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 = settings.MaxDepths,
							MaxBidsDepth = settings.MaxDepths,
							UseTradeVolume = true,
							MaxVolume = settings.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;
				}
			};

			_connector.Disconnected += () =>
			{
				this.GuiAsync(() => _connector.Dispose());
			};

			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 #12
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 #13
0
        public void Connect()
        {
            trader = new IQFeedTrader();
            trader.Connected += () => SetConnectionStatus(0);
            trader.Disconnected += () => SetConnectionStatus(1);
            trader.ConnectionError += error => SetConnectionStatus(error);

            trader.Connect();

            var monitor = new MonitorWindow();
            monitor.Show();

            logManager.Listeners.Add(new GuiLogListener(monitor));
            logManager.Sources.Add(trader);

            var address = IPAddress.Parse("72.5.42.156");

            Trader = new BlackwoodTrader();
            logManager.Sources.Add(Trader);

            Trader.Login = "******";
            Trader.Password = "******";
            Trader.ExecutionAddress = new IPEndPoint(address, BlackwoodAddresses.ExecutionPort);
            Trader.MarketDataAddress = new IPEndPoint(address, BlackwoodAddresses.MarketDataPort);
            Trader.HistoricalDataAddress = new IPEndPoint(address, BlackwoodAddresses.HistoricalDataPort);

            Trader.Connected += Trader_Connected;
            Trader.ConnectionError += Trader_ConnectionError;
            Trader.Disconnected += Trader_Disconnected;

            Trader.NewPortfolios += portfolios =>
            {
                foreach (var portfolio in portfolios)
                {
                    Portfolio = portfolio;
                    Debug.Print("Portfolio name {0}", portfolio.Name);
                    Debug.Print("Portfolio RealizedPnL {0}", portfolio.RealizedPnL);
                    Debug.Print("Portfolio UnrealizedPnL {0}", portfolio.UnrealizedPnL);
                }
            };

            Trader.NewCandles += Trader_NewCandles;

            Trader.NewOrders += Trader_NewOrders;
            Trader.NewPositions += Trader_NewPositions;
            Trader.Connect();
        }
        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;
        }
		/// <summary>
		/// Create position.
		/// </summary>
		/// <param name="portfolio">Portfolio.</param>
		/// <param name="security">Security.</param>
		/// <returns>Created position.</returns>
		public override Position CreatePosition(Portfolio portfolio, Security security)
		{
			return _entityRegistry.Positions.ReadBySecurityAndPortfolio(security, portfolio)
			       ?? base.CreatePosition(portfolio, security);
		}
Example #16
0
		/// <summary>
		/// The selected item change event handler.
		/// </summary>
		/// <param name="e">The event parameter.</param>
		protected override void OnSelectionChanged(SelectionChangedEventArgs e)
		{
			SelectedPortfolio = (Portfolio)SelectedItem;
			base.OnSelectionChanged(e);
		}
Example #17
0
		private void StartBtnClick(object sender, RoutedEventArgs e)
		{
			// if process was already started, will stop it now
			if (_connector != null && _connector.State != EmulationStates.Stopped)
			{
				_strategy.Stop();
				_connector.Disconnect();
				_logManager.Sources.Clear();

				_connector = null;
				return;
			}

			// create test security
			var security = new Security
			{
				Id = "AAPL@NASDAQ",
				Code = "AAPL",
				Name = "AAPL Inc",
				Board = ExchangeBoard.Nasdaq,
			};

			var startTime = new DateTime(2009, 6, 1);
			var stopTime = new DateTime(2009, 9, 1);

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

			var timeFrame = TimeSpan.FromMinutes(5);

			// create backtesting connector
			_connector = new HistoryEmulationConnector(
				new[] { security },
				new[] { portfolio })
			{
				HistoryMessageAdapter =
				{
					// set history range
					StartDate = startTime,
					StopDate = stopTime,
				},

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

			_logManager.Sources.Add(_connector);

			var candleManager = new CandleManager(_connector);

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

			// create strategy based on 80 5-min и 10 5-min
			_strategy = new SmaStrategy(series, new SimpleMovingAverage { Length = 80 }, new SimpleMovingAverage { Length = 10 })
			{
				Volume = 1,
				Security = security,
				Portfolio = portfolio,
				Connector = _connector,
			};

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

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

				_connector.RegisterTrades(new RandomWalkTradeGenerator(_connector.GetSecurityId(security)));
				_connector.RegisterMarketDepth(new TrendMarketDepthGenerator(_connector.GetSecurityId(security)) { GenerateDepthOnEachTrade = false });

				// 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
			ParameterGrid.Parameters.Clear();
			ParameterGrid.Parameters.AddRange(_strategy.StatisticManager.Parameters);

			_strategy.PnLChanged += () =>
			{
				var data = new EquityData
				{
					Time = _strategy.CurrentTime,
					Value = _strategy.PnL,
				};

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

			_logManager.Sources.Add(_strategy);

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

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

			// handle historical time for update ProgressBar
			_connector.MarketTimeChanged += diff =>
			{
				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(() => TestingProcess.Value = steps);
			};

			_connector.StateChanged += () =>
			{
				if (_connector.State == EmulationStates.Stopped)
				{
					this.GuiAsync(() =>
					{
						Report.IsEnabled = true;

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

			_curveItems.Clear();

			Report.IsEnabled = false;

			_startEmulationTime = DateTime.Now;

			// raise NewSecurities and NewPortfolio for full fill strategy properties
			_connector.Connect();
		}
Example #18
0
        static void Main()
        {
            try
            {
                // для теста выбираем бумагу Лукойл
                const string secCode = "LKOH";

                var quikPath = QuikTerminal.GetDefaultPath();

                if (quikPath.IsEmpty())
                {
                    Console.WriteLine("Не найден ни один запущенный Quik");
                    return;
                }

                Console.WriteLine("Запущенный Quik найден по пути " + quikPath);

                Console.Write("Введите код клиента, через который будет выставлена заявка: ");
                var account = Console.ReadLine();

                using (var waitHandle = new AutoResetEvent(false))
                {
                    // создаем шлюз к Quik-у
                    using (var trader = new QuikTrader(quikPath))
                    {
                        // необходимо раскомментировать, если идет работа с РТС Стандарт
                        //trader.FormatTransaction += builder => builder.RemoveInstruction(TransactionBuilder.ExecutionCondition);

                        // подписываемся на событие успешного подключения
                        // все действия необходимо производить только после подключения
                        trader.Connected += () =>
                        {
                            Console.WriteLine("Подключение было произведено успешно.");

                            // извещаем об успешном соединени
                            waitHandle.Set();
                        };

                        Console.WriteLine("Производим подключение...");

                        trader.Connect();

                        // дожидаемся события об успешном соединении
                        waitHandle.WaitOne();

                        trader.NewPortfolios += portfolios =>
                        {
                            if (_portfolio == null)
                            {
                                // находим Лукойл и присваиваем ее переменной lkoh
                                _portfolio = portfolios.FirstOrDefault(p => p.Name == account);

                                if (_portfolio != null)
                                {
                                    Console.WriteLine("Портфель {0} появился.", account);

                                    // если инструмент и стакан уже появились,
                                    // то извещаем об этом основной поток для выставления заявки
                                    if (_lkoh != null && _depth != null)
                                        waitHandle.Set();
                                }
                            }
                        };

                        // подписываемся на событие появление инструментов
                        trader.NewSecurities += securities =>
                        {
                            if (_lkoh == null)
                            {
                                // находим Лукойл и присваиваем ее переменной lkoh
                                _lkoh = securities.FirstOrDefault(sec => sec.Code == secCode);

                                if (_lkoh != null)
                                {
                                    Console.WriteLine("Инструмент Лукойл появился.");

                                    // запускаем экспорт стакана
                                    trader.RegisterQuotes(_lkoh);

                                    if (_portfolio != null && _depth != null)
                                        waitHandle.Set();
                                }
                            }
                        };

                        // подписываемся на событие появления моих новых сделок
                        trader.NewMyTrades += myTrades =>
                        {
                            foreach (var myTrade in myTrades)
                            {
                                var trade = myTrade.Trade;
                                Console.WriteLine("Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}.", trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
                            }
                        };

                        // подписываемся на событие обновления стакана
                        trader.QuotesChanged += depths =>
                        {
                            if (_depth == null && _lkoh != null)
                            {
                                _depth = depths.FirstOrDefault(d => d.Security == _lkoh);

                                if (_depth != null)
                                {
                                    Console.WriteLine("Стакан Лукойла появился.");

                                    // если портфель и инструмент уже появился, то извещаем об этом основной поток для выставления заявки
                                    if (_portfolio != null && _lkoh != null)
                                        waitHandle.Set();
                                }
                            }
                        };

                        Console.WriteLine("Дожидаемся появления в программе инструмента Лукойл и портфеля {0}...".Put(account));

                        // запускаем экспорт по DDE
                        trader.StartExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
                                           trader.EquityPortfoliosTable, trader.OrdersTable);

                        // дожидаемся появления портфеля и инструмента
                        waitHandle.WaitOne();

                        // 0.1% от изменения цены
                        const decimal delta = 0.001m;

                        // запоминаем первоначальное значение середины спреда
                        var firstMid = _lkoh.BestPair.SpreadPrice / 2;
                        if (_lkoh.BestBid == null)
                            throw new Exception("Нет лучшего бида для котировки.");

                        Console.WriteLine("Первоначальное значение середины спреда {0:0.##}", _lkoh.BestBid.Price + firstMid);

                        while (true)
                        {
                            var mid = _lkoh.BestPair.SpreadPrice / 2;

                            // если спред вышел за пределы нашего диапазона
                            if	(
                                    ((firstMid + firstMid * delta) <= mid) ||
                                    ((firstMid - firstMid * delta) >= mid)
                                )
                            {
                                var order = new Order
                                {
                                    Portfolio = _portfolio,
                                    Price = _lkoh.ShrinkPrice(_lkoh.BestBid.Price + mid),
                                    Security = _lkoh,
                                    Volume = 1,
                                    Direction = OrderDirections.Buy,
                                };
                                trader.RegisterOrder(order);
                                Console.WriteLine("Заявка {0} зарегистрирована.", order.Id);
                                break;
                            }
                            else
                                Console.WriteLine("Текущее значение середины спреда {0:0.##}", _lkoh.BestBid.Price + mid);

                            // ждем 1 секунду
                            Thread.Sleep(1000);
                        }

                        // останавливаем экспорт по DDE
                        trader.StopExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
                                          trader.EquityPortfoliosTable, trader.OrdersTable);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
		private void ClearCommand_OnExecuted(object sender, ExecutedRoutedEventArgs e)
		{
			SelectedPortfolio = null;
		}
Example #20
0
		static void Main()
		{
			try
			{
				// для теста выбираем бумагу Лукойл
				const string secCode = "LKOH";

				Console.Write(LocalizedStrings.EnterLogin);
				var login = Console.ReadLine();

				Console.Write(LocalizedStrings.EnterPassword);
				var password = Console.ReadLine();

				Console.Write("Enter account number through which an order will be placed:".Translate());
				var account = Console.ReadLine();

				using (var waitHandle = new AutoResetEvent(false))
				{
					// создаем подключение к Smart-у
					using (var trader = new SmartTrader { Login = login, Password = password, Address = SmartComAddresses.Demo })
					{
						// подписываемся на событие успешного подключения
						// все действия необходимо производить только после подключения
						trader.Connected += () =>
						{
							Console.WriteLine(LocalizedStrings.Str2169);

							// извещаем об успешном соединени
							waitHandle.Set();
						};

						Console.WriteLine(LocalizedStrings.Str2170);

						trader.Connect();

						// дожидаемся события об успешном соединении
						waitHandle.WaitOne();

						// подписываемся на все портфели-счета
						trader.NewPortfolios += portfolios =>
						{
							if (_portfolio != null)
								return;

							// находим нужный портфель и присваиваем его переменной _portfolio
							_portfolio = portfolios.FirstOrDefault(p => p.Name == account);

							if (_portfolio == null)
								return;

							Console.WriteLine(LocalizedStrings.Str2171Params, account);

							if (_lkoh != null)
								waitHandle.Set();
						};

						// подписываемся на событие появление инструментов
						trader.NewSecurities += securities =>
						{
							if (_lkoh == null)
							{
								// находим Лукойл и присваиваем ее переменной lkoh
								_lkoh = securities.FirstOrDefault(sec => sec.Code == secCode && sec.Type == SecurityTypes.Stock);

								if (_lkoh != null)
								{
									Console.WriteLine(LocalizedStrings.Str2987);

									if (_portfolio != null)
										waitHandle.Set();
								}
							}
						};

						// подписываемся на событие появления моих новых сделок
						trader.NewMyTrades += myTrades =>
						{
							foreach (var myTrade in myTrades)
							{
								var trade = myTrade.Trade;
								Console.WriteLine(LocalizedStrings.Str2173Params, trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
							}
						};

						Console.WriteLine(LocalizedStrings.Str2989Params.Put(account));

						// дожидаемся появления портфеля и инструмента
						waitHandle.WaitOne();

						trader.SecuritiesChanged += securities =>
						{
							// если инструмент хоть раз изменился (по нему пришли актуальные данные)
							if (securities.Contains(_lkoh) && _lkoh.BestBid != null && _lkoh.BestAsk != null)
								waitHandle.Set();
						};

						Console.WriteLine("Waiting for Lukoil security data to update...".Translate());

						// запускаем обновление по инструменту
						trader.RegisterSecurity(_lkoh);
						waitHandle.WaitOne();

						// 0.1% от изменения цены
						const decimal delta = 0.001m;

						// запоминаем первоначальное значение середины спреда
						var firstMid = _lkoh.BestPair.SpreadPrice / 2;
						if (_lkoh.BestBid == null || firstMid == null)
							throw new Exception(LocalizedStrings.Str2990);

						Console.WriteLine(LocalizedStrings.Str2991Params, _lkoh.BestBid.Price + firstMid);

						while (true)
						{
							var mid = _lkoh.BestPair.SpreadPrice / 2;

							// если спред вышел за пределы нашего диапазона
							if (mid != null &&
								((firstMid + firstMid * delta) <= mid ||
								(firstMid - firstMid * delta) >= mid)
								)
							{
								var order = new Order
								{
									Portfolio = _portfolio,
									Price = _lkoh.ShrinkPrice(_lkoh.BestBid.Price + mid.Value),
									Security = _lkoh,
									Volume = 1,
									Direction = Sides.Buy,
								};
								trader.RegisterOrder(order);
								Console.WriteLine(LocalizedStrings.Str1157Params, order.Id);
								break;
							}
							else
								Console.WriteLine(LocalizedStrings.Str2176Params, _lkoh.BestBid.Price + mid);

							// ждем 1 секунду
							Thread.Sleep(1000);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
			}
		}
		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 #22
0
		static void Main()
		{
			try
			{
				// для теста выбираем бумагу Лукойл
				const string secCode = "LKOH";

				var quikPath = QuikTerminal.GetDefaultPath();

				if (quikPath.IsEmpty())
				{
					Console.WriteLine(LocalizedStrings.Str2984);
					return;
				}

				Console.WriteLine(LocalizedStrings.Str2985 + quikPath);

				Console.Write(LocalizedStrings.Str2986);
				var account = Console.ReadLine();

				using (var waitHandle = new AutoResetEvent(false))
				{
					// создаем подключение к Quik-у
					using (var trader = new QuikTrader(quikPath) { IsDde = true })
					{
						// необходимо раскомментировать, если идет работа с РТС Стандарт
						//trader.FormatTransaction += builder => builder.RemoveInstruction(Transaction.TimeInForce);

						// подписываемся на событие успешного подключения
						// все действия необходимо производить только после подключения
						trader.Connected += () =>
						{
							Console.WriteLine(LocalizedStrings.Str2169);

							// извещаем об успешном соединени
							waitHandle.Set();
						};

						Console.WriteLine(LocalizedStrings.Str2170);

						trader.DdeTables = new[] { trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
						                   trader.EquityPortfoliosTable, trader.OrdersTable };

						trader.Connect();

						// дожидаемся события об успешном соединении
						waitHandle.WaitOne();

						trader.NewPortfolios += portfolios =>
						{
							if (_portfolio == null)
							{
								// находим нужный портфель и присваиваем его переменной _portfolio
								_portfolio = portfolios.FirstOrDefault(p => p.Name == account);

								if (_portfolio != null)
								{
									Console.WriteLine(LocalizedStrings.Str2171Params, account);

									// если инструмент и стакан уже появились,
									// то извещаем об этом основной поток для выставления заявки
									if (_lkoh != null && _depth != null)
										waitHandle.Set();
								}
							}
						};

						// подписываемся на событие появление инструментов
						trader.NewSecurities += securities =>
						{
							if (_lkoh == null)
							{
								// находим Лукойл и присваиваем ее переменной lkoh
								_lkoh = securities.FirstOrDefault(sec => sec.Code == secCode);

								if (_lkoh != null)
								{
									Console.WriteLine(LocalizedStrings.Str2987);

									// запускаем экспорт стакана
									trader.RegisterMarketDepth(_lkoh);

									if (_portfolio != null && _depth != null)
										waitHandle.Set();
								}
							}
						};

						// подписываемся на событие появления моих новых сделок
						trader.NewMyTrades += myTrades =>
						{
							foreach (var myTrade in myTrades)
							{
								var trade = myTrade.Trade;
								Console.WriteLine(LocalizedStrings.Str2173Params, trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
							}
						};

						// подписываемся на событие обновления стакана
						trader.MarketDepthsChanged += depths =>
						{
							if (_depth == null && _lkoh != null)
							{
								_depth = depths.FirstOrDefault(d => d.Security == _lkoh);

								if (_depth != null)
								{
									Console.WriteLine(LocalizedStrings.Str2988);

									// если портфель и инструмент уже появился, то извещаем об этом основной поток для выставления заявки
									if (_portfolio != null && _lkoh != null)
										waitHandle.Set();
								}
							}
						};

						Console.WriteLine(LocalizedStrings.Str2989Params.Put(account));

						// дожидаемся появления портфеля и инструмента
						waitHandle.WaitOne();

						// 0.1% от изменения цены
						const decimal delta = 0.001m;

						// запоминаем первоначальное значение середины спреда
						var firstMid = _lkoh.BestPair.SpreadPrice / 2;
						if (_lkoh.BestBid == null || firstMid == null)
							throw new Exception(LocalizedStrings.Str2990);

						Console.WriteLine(LocalizedStrings.Str2991Params, _lkoh.BestBid.Price + firstMid);

						while (true)
						{
							var mid = _lkoh.BestPair.SpreadPrice / 2;

							// если спред вышел за пределы нашего диапазона
							if (mid != null &&
									((firstMid + firstMid * delta) <= mid ||
									(firstMid - firstMid * delta) >= mid)
								)
							{
								var order = new Order
								{
									Portfolio = _portfolio,
									Price = _lkoh.ShrinkPrice(_lkoh.BestBid.Price + mid.Value),
									Security = _lkoh,
									Volume = 1,
									Direction = Sides.Buy,
								};
								trader.RegisterOrder(order);
								Console.WriteLine(LocalizedStrings.Str1157Params, order.Id);
								break;
							}
							else
								Console.WriteLine(LocalizedStrings.Str2176Params, _lkoh.BestBid.Price + mid);

							// ждем 1 секунду
							Thread.Sleep(1000);
						}

						// останавливаем подключение
						trader.Disconnect();
					}
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
			}
		}
Example #23
0
		private void LookupPortfolio(IEnumerable<Portfolio> portfolios)
		{
			_portfolio = portfolios.FirstOrDefault(port => port.Name == _strategyConfiguration.PortfolioName);
			if (_portfolio != null)
			{
				PortfolioFoundEvent.Set();
			}
		}
Example #24
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 #25
0
		/// <summary>
		/// Скопировать поля текущего портфеля в <paramref name="destination"/>.
		/// </summary>
		/// <param name="destination">Портфель, в который необходимо скопировать поля.</param>
		public void CopyTo(Portfolio destination)
		{
			base.CopyTo(destination);

			destination.Name = Name;
			destination.Board = Board;
			destination.Currency = Currency;
			destination.Leverage = Leverage;
			destination.Connector = Connector;
			destination.State = State;
		}
		private void Button_Click(object sender, RoutedEventArgs e)
		{
			var wnd = new PortfolioPickerWindow
			{
				Connector = Connector,
			};

			if (wnd.ShowModal(this))
			{
				SelectedPortfolio = wnd.SelectedPortfolio;
			}
		}
		//private void InitOrderLogBuilders(DateTime loadDate)
		//{
		//	if (StorageRegistry == null || !MarketEmulator.Settings.UseMarketDepth)
		//		return;

		//	foreach (var security in RegisteredMarketDepths)
		//	{
		//		var builder = _orderLogBuilders.TryGetValue(security);

		//		if (builder == null)
		//			continue;

		//		// стакан из ОЛ строиться начиная с 18.45 предыдущей торговой сессии
		//		var olDate = loadDate.Date;

		//		do
		//		{
		//			olDate -= TimeSpan.FromDays(1);
		//		}
		//		while (!ExchangeBoard.Forts.WorkingTime.IsTradeDate(olDate));

		//		olDate += new TimeSpan(18, 45, 0);

		//		foreach (var item in StorageRegistry.GetOrderLogStorage(security, Drive).Load(olDate, loadDate - TimeSpan.FromTicks(1)))
		//		{
		//			builder.Update(item);
		//		}
		//	}
		//}

		///// <summary>
		///// Найти инструменты, соответствующие фильтру <paramref name="criteria"/>.
		///// </summary>
		///// <param name="criteria">Инструмент, поля которого будут использоваться в качестве фильтра.</param>
		///// <returns>Найденные инструменты.</returns>
		//public override IEnumerable<Security> Lookup(Security criteria)
		//{
		//	var securities = _historyAdapter.SecurityProvider.Lookup(criteria);

		//	if (State == EmulationStates.Started)
		//	{
		//		foreach (var security in securities)
		//			SendSecurity(security);	
		//	}

		//	return securities;
		//}

		/// <summary>
		/// Subscribe on the portfolio changes.
		/// </summary>
		/// <param name="portfolio">Portfolio for subscription.</param>
		protected override void OnRegisterPortfolio(Portfolio portfolio)
		{
			_initialMoney.TryAdd(portfolio, portfolio.BeginValue);

			if (State == EmulationStates.Started)
				SendPortfolio(portfolio);
		}
Example #28
0
		private void RaiseNewPortfolio(Portfolio portfolio)
		{
			NewPortfolio.SafeInvoke(portfolio);

			var multiEvt = NewPortfolios;

			if (multiEvt == null)
				return;

			multiEvt.SafeInvoke(new[] { portfolio });
		}
Example #29
0
		public Position TryAddPosition(Portfolio portfolio, Security security, string depoName, TPlusLimits? limitType, string description, out bool isNew)
		{
			isNew = false;
			Position position;

			lock (_positions.SyncRoot)
			{
				if (depoName == null)
					depoName = string.Empty;

				var key = Tuple.Create(portfolio, security, depoName, limitType);

				if (!_positions.TryGetValue(key, out position))
				{
					isNew = true;

					position = EntityFactory.CreatePosition(portfolio, security);
					position.DepoName = depoName;
					position.LimitType = limitType;
					position.Description = description;
					_positions.Add(key, position);
				}
			}

			return position;
		}
Example #30
0
		private void RaisePortfolioChanged(Portfolio portfolio)
		{
			PortfolioChanged.SafeInvoke(portfolio);

			var multiEvt = PortfoliosChanged;

			if (multiEvt == null)
				return;

			multiEvt.SafeInvoke(new[] { portfolio });
		}