public override List <Candle> GetAllFrom(string database, string dataId, int resolution) { CandleManager cm = new CandleManager(DB); int id = cm.LoadFromDB(dataId, resolution); return(cm.GetCandleList(id, resolution)); }
/// <summary> /// внутренняя функция запускающая процесс соединения с Плазой /// </summary> private void Connecting() { _lastStartServerTime = DateTime.Now; if (_plazaController == null) { _plazaController = new PlazaController(KeyToProggram); _plazaController.LogMessageEvent += _plazaController_LogMessageEvent; _plazaController.ConnectStatusChangeEvent += _plazaController_StatusChangeEvent; _plazaController.MarketDepthChangeEvent += _plazaController_UpdateGlass; _plazaController.NewMyTradeEvent += _plazaController_UpdateMyTrade; _plazaController.NewMyOrderEvent += _plazaController_UpdateOrders; _plazaController.UpdatePortfolio += _plazaController_UpdatePortfolios; _plazaController.UpdatePosition += _plazaController_UpdatePosition; _plazaController.UpdateSecurity += _plazaController_UpdateSecurity; _plazaController.NewTradeEvent += _plazaController_UpdateTrade; } if (_candleManager == null) { _candleManager = new CandleManager(this); _candleManager.CandleUpdateEvent += _candleManager_CandleUpdateEvent; _candleManager.LogMessageEvent += SendNewLogMessage; } _plazaController.Start(); }
public ChartWindow(CandleSeries candleSeries, DateTime from, DateTime to) { InitializeComponent(); if (candleSeries == null) { throw new ArgumentNullException(nameof(candleSeries)); } _candleSeries = candleSeries; _trader = MainWindow.Instance.Trader; Chart.ChartTheme = ChartThemes.ExpressionDark; var area = new ChartArea(); Chart.Areas.Add(area); _candleElem = new ChartCandleElement { AntiAliasing = false, UpFillColor = Colors.White, UpBorderColor = Colors.Black, DownFillColor = Colors.Black, DownBorderColor = Colors.Black, }; area.Elements.Add(_candleElem); _manager = new CandleManager(_trader); _manager.Processing += ProcessNewCandles; _manager.Start(_candleSeries, from, to); }
public override List <Candle> GetAllFrom(int dataId, int resolution) { CandleManager cm = new CandleManager(DB); cm.LoadFromDB(dataId, resolution); return(cm.GetCandleList(dataId, resolution)); }
private CandleManager CreateCandleManager() { var candleManager = new CandleManager(EmulationConnector); candleManager.Sources.RemoveWhere(s => s is StorageCandleSource); return(candleManager); }
private void OnConnect() { _connector = new QuikTrader() { LuaFixServerAddress = "127.0.0.1:5002".To <EndPoint>() }; SecurityEditor.SecurityProvider = _connector; _candleManager = new CandleManager(_connector); _connector.Connected += () => { this.GuiAsync(() => { StatusTextBlock.Text = "Соединение установлено!"; ConnectButtom.Content = "Разъединить"; }); }; _connector.Disconnected += () => { this.GuiAsync(() => { StatusTextBlock.Text = "Соединение разорвано!"; ConnectButtom.Content = "Соединить"; }); }; // Это обработчик событие получения свечи _candleManager.Processing += (series, candle) => { if (series != _series) { return; } // Используем только завершенные свечи if (candle.State != CandleStates.Finished) { return; } // Рассчитываем значение индикатора var smaValue = _sma.Process(candle); // Создаем экземпляр класса ChartDrawData - класс, где группируются данные для отрисовки var data = new ChartDrawData(); // chartItem - набор элементов, привязанных к одной точке на шкале X var chartItem = data.Group(candle.OpenTime).Add(_candleElement, candle); chartItem.Add(_indicatorElement, smaValue); // Безопасно отрисовываем элементы на графике this.GuiSync(() => { Chart.Draw(data); }); }; _connector.Connect(); }
/// <summary> /// запускает скачиватель свечек /// </summary> private void StartCandleManager() { if (_candleManager == null) { _candleManager = new CandleManager(this); _candleManager.CandleUpdateEvent += _candleManager_CandleUpdateEvent; _candleManager.LogMessageEvent += SendLogMessage; } }
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(); } }
private void ConnectClick(object sender, RoutedEventArgs e) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } // создаем подключение _trader = new SmartTrader { Login = Login.Text, Password = Password.Password, Address = Address.SelectedAddress, // применить нужную версию SmartCOM Version = IsSmartCom3.IsChecked == true ? SmartComVersions.V3 : SmartComVersions.V2, }; // очищаем из текстового поля в целях безопасности //Password.Clear(); // подписываемся на ошибку обработки данных (транзакций и маркет) _trader.ProcessDataError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // подписываемся на ошибку подписки маркет-данных _trader.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); _trader.NewSecurities += securities => { // так как инструментов слишком много, то выводим только два популярных с ММВБ и РТС securities = securities.Where(s => s.Code == "LKOH" || (s.Type == SecurityTypes.Future && s.Id.Like("RI%FORTS"))); this.GuiAsync(() => _securitiesSource.AddRange(securities)); // начинаем получать текущие сделки (для построения свечек в реальном времени) securities.ForEach(_trader.RegisterTrades); }; // запускаем экспорт в случае успешного подключения _trader.Connected += _trader.StartExport; _candleManager = new CandleManager(_trader); _trader.Connect(); ConnectBtn.IsEnabled = false; }
// Вот так можно создать CandleManager с произвольной коллекцией данных // В нашем случае используются сделки, но это могут быть стаканы или записи ордерлога private static CandleManager CreateCandleManager(Connector connector, Security security) { var trades = connector.Trades.Where(t => t.Security == security); // некая коллекция сделок var source = new RawConvertableCandleBuilderSource <Trade>(security, DateTimeOffset.MinValue, DateTimeOffset.MaxValue, trades); CandleManager candleManager = null; candleManager = new CandleManager(source); // Вот так можно добавить источник к уже существующему CandleManager ///candleManager.Sources.Add((ICandleManagerSource)source); return(candleManager); }
private void ConnectClick(object sender, RoutedEventArgs e) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } // создаем подключение _trader = new SmartTrader { Login = Login.Text, Password = Password.Password, Address = Address.SelectedAddress, // применить нужную версию SmartCOM Version = IsSmartCom3.IsChecked == true ? SmartComVersions.V3 : SmartComVersions.V2, }; // очищаем из текстового поля в целях безопасности //Password.Clear(); // подписываемся на ошибку обработки данных (транзакций и маркет) _trader.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // подписываемся на ошибку подписки маркет-данных _trader.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); _trader.NewSecurities += securities => { // так как инструментов слишком много, то выводим только два популярных с ММВБ и РТС securities = securities.Where(s => s.Code == "LKOH" || (s.Type == SecurityTypes.Future && s.Id.Like("RI%FORTS"))); this.GuiAsync(() => _securitiesSource.AddRange(securities)); }; _candleManager = new CandleManager(_trader); _trader.Connect(); ConnectBtn.IsEnabled = false; }
private void ConnectClick(object sender, RoutedEventArgs e) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } // создаем подключение _trader = new SmartTrader { Login = Login.Text, Password = Password.Password, Address = Address.SelectedAddress, // применить нужную версию SmartCOM Version = IsSmartCom3.IsChecked == true ? SmartComVersions.V3 : SmartComVersions.V2, }; // очищаем из текстового поля в целях безопасности //Password.Clear(); // подписываемся на ошибку обработки данных (транзакций и маркет) _trader.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // подписываемся на ошибку подписки маркет-данных _trader.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); Security.SecurityProvider = new FilterableSecurityProvider(_trader); _candleManager = new CandleManager(_trader); _trader.Connect(); ConnectBtn.IsEnabled = false; }
public QshServer() { _qshClient = new QshClient(); _qshClient.NewDataFromQsh += _qshClient_NewDataFromQsh; if (_worker == null) { _worker = new Thread(WorkThreadArea); _worker.CurrentCulture = CultureInfo; _worker.IsBackground = true; _worker.Name = "TesterServerThread"; _worker.Start(); } NamesPaper = new List <string>(); _alltrades = new List <Trade>(); CreatePortfolio(); _candleManager = new CandleManager(this); _candleManager.CandleUpdateEvent += _candleManager_CandleUpdateEvent;; _candleManager.LogMessageEvent += _candleManager_LogMessageEvent;; ConnectStatusChangeEvent += QshServer_ConnectStatusChangeEvent; //LoadSettings(); //_pathToFolder = "C:\\QSH_archive\\"; if (_pathToFolder != "") { _needToReloadSecurities = true; } ServerStatus = ServerConnectStatus.Disconnect; OrdersActiv = new List <Order>(); _slipageToStopOrder = 0; _slipageToSimpleOrder = 0; }
private void Connector_RxNewSecurity(Security security) { _connector.RegisterTrades(security); _candleManager = new CandleManager(_connector); _candleManager.RxWhenCandlesChanged(_candleSeries).Subscribe(CandleManager_RxWhenCandlesChanged); _strategy = new MyRxStrategy(_candleSeries) { Security = _security, Connector = _connector, Portfolio = _portfolio, }; _strategy.SetCandleManager(_candleManager); _strategy.RxNewMyTrade().Subscribe(MyTradeGrid.Trades.Add); _strategy.RxNewMyTrade().Subscribe(FirstStrategy_NewMyTrade); _strategy.Start(); _candleManager.Start(_candleSeries); _connector.Start(); }
private void ConnectClick(object sender, RoutedEventArgs e) { if (Path.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2983); } else { _trader = new QuikTrader(Path.Text) { IsDde = true }; _trader.Connected += () => this.GuiAsync(() => ExportDde.IsEnabled = true); _trader.NewSecurities += securities => this.GuiAsync(() => Security.ItemsSource = _trader.Securities); _trader.Connect(); _candleManager = new CandleManager(_trader); _candleManager.Processing += DrawCandle; ConnectBtn.IsEnabled = false; } }
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(); }
private void ConnectClick(object sender, RoutedEventArgs e) { if (!_isConnected) { if (_connector == null) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } // create real-time emu connector _connector = new RealTimeEmulationTrader<Connector>(new SmartTrader { Login = Login.Text, Password = Password.Password, Address = Address.SelectedAddress }); //_connector = new RealTimeEmulationTrader<Connector>(new PlazaTrader //{ // IsCGate = true, //}, portfolio); SecurityEditor.SecurityProvider = new FilterableSecurityProvider(_connector); _logManager.Sources.Add(_connector); // clear password for security reason //Password.Clear(); // subscribe on connection successfully event _connector.Connected += () => { // set flag (connection is established) _isConnected = true; // update gui labels this.GuiAsync(() => ChangeConnectStatus(true)); _candleManager = new CandleManager(_connector); _connector.NewMarketDepths += OnDepths; _connector.MarketDepthsChanged += OnDepths; _connector.NewOrders += orders => Orders.Orders.AddRange(orders); _connector.NewMyTrades += trades => Trades.Trades.AddRange(trades); // подписываемся на событие о неудачной регистрации заявок _connector.OrdersRegisterFailed += OrdersFailed; _candleManager.Processing += (s, candle) => { if (candle.State == CandleStates.Finished) _buffer.Add(candle); }; this.GuiAsync(() => { ConnectBtn.IsEnabled = false; }); }; // subscribe on connection error event _connector.ConnectionError += error => this.GuiAsync(() => { // update gui labels ChangeConnectStatus(false); MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2959); }); // subscribe on error event _connector.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // subscribe on error of market data subscription event _connector.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); } _connector.Connect(); } else { _connector.Disconnect(); } }
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.Str3017}), Tuple.Create( TicksAndDepthsCheckBox, TicksAndDepthsTestingProcess, TicksAndDepthsParameterGrid, // ticks + order book new EmulationInfo {UseTicks = true, UseMarketDepth = true, CurveColor = Colors.Red, StrategyName = LocalizedStrings.Str3018}), Tuple.Create( CandlesCheckBox, CandlesTestingProcess, CandlesParameterGrid, // candles new EmulationInfo {UseCandleTimeFrame = timeFrame, CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.Str3019}), Tuple.Create( CandlesAndDepthsCheckBox, CandlesAndDepthsTestingProcess, CandlesAndDepthsParameterGrid, // candles + orderbook new EmulationInfo {UseMarketDepth = true, UseCandleTimeFrame = timeFrame, CurveColor = Colors.Cyan, StrategyName = LocalizedStrings.Str3020}), Tuple.Create( OrderLogCheckBox, OrderLogTestingProcess, OrderLogParameterGrid, // order log new EmulationInfo {UseOrderLog = true, CurveColor = Colors.CornflowerBlue, StrategyName = LocalizedStrings.Str3021}) }; // storage to historical data var storageRegistry = new StorageRegistry { // set historical path 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 refresh step var progressStep = ((stopTime - startTime).Ticks / 100).To<TimeSpan>(); // set ProgressBar bounds 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()); // 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 }) { StorageRegistry = storageRegistry, MarketEmulator = { Settings = { // set time frame is backtesting on candles UseCandlesTimeFrame = emulationInfo.UseCandleTimeFrame, // 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 = true, CreateDepthFromOrdersLog = emulationInfo.UseOrderLog, CreateTradesFromOrdersLog = emulationInfo.UseOrderLog, // 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 = 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; }
private void StartBtnClick(object sender, RoutedEventArgs e) { // если процесс был запущен, то его останавливаем if (_connector != null) { _strategy.Stop(); _connector.Stop(); _logManager.Sources.Clear(); _connector = null; return; } // создаем тестовый инструмент, на котором будет производится тестирование var security = new Security { Id = "RIU9@FORTS", Code = "RIU9", Name = "RTS-9.09", Board = ExchangeBoard.Forts, }; 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); // тестовый портфель var portfolio = new Portfolio { Name = "test account", BeginValue = 1000000, }; var timeFrame = TimeSpan.FromMinutes(5); // создаем подключение для эмуляции _connector = new HistoryEmulationConnector( new[] { security }, new[] { portfolio }); _connector.MarketDataAdapter.SessionHolder.MarketTimeChangedInterval = timeFrame; _logManager.Sources.Add(_connector); _connector.NewSecurities += securities => { if (securities.All(s => s != security)) { return; } // отправляем данные Level1 для инструмента _connector.MarketDataAdapter.SendOutMessage(level1Info); _connector.RegisterTrades(new RandomWalkTradeGenerator(_connector.GetSecurityId(security))); _connector.RegisterMarketDepth(new TrendMarketDepthGenerator(_connector.GetSecurityId(security)) { GenerateDepthOnEachTrade = false }); }; // соединяемся с трейдером и запускаем экспорт, // чтобы инициализировать переданными инструментами и портфелями необходимые свойства EmulationTrader _connector.Connect(); _connector.StartExport(); var candleManager = new CandleManager(_connector); var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame); // создаем торговую стратегию, скользящие средние на 80 5-минуток и 10 5-минуток _strategy = new SmaStrategy(series, new SimpleMovingAverage { Length = 80 }, new SimpleMovingAverage { Length = 10 }) { Volume = 1, Security = security, Portfolio = portfolio, Connector = _connector, }; // копируем параметры на визуальную панель 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 var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>(); var nextTime = startTime + progressStep; TestingProcess.Maximum = 100; TestingProcess.Value = 0; // и подписываемся на событие изменения времени, чтобы обновить 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(LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime)); } else { MessageBox.Show(LocalizedStrings.cancelled); } }); } else if (_connector.State == EmulationStates.Started) { // запускаем стратегию когда эмулятор запустился _strategy.Start(); candleManager.Start(series); } }; if (_curveItems == null) { _curveItems = Curve.CreateCurve(_strategy.Name, Colors.DarkGreen); } else { _curveItems.Clear(); } Report.IsEnabled = false; _startEmulationTime = DateTime.Now; // запускаем эмуляцию _connector.Start(new DateTime(2009, 6, 1), new DateTime(2009, 9, 1)); }
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(candleManager, series, new SimpleMovingAverage { Length = 80 }, new SimpleMovingAverage { Length = 10 }) { Volume = 1, Security = security, Portfolio = portfolio, Connector = _connector, }; _connector.NewSecurity += s => { if (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(); }
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); }); // start emulation batchEmulation.Start(strategies); }
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); }); }; // 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); }
private void ConnectClick(object sender, RoutedEventArgs e) { if (!_isConnected) { if (_connector == null) { if (SmartCom.IsChecked == true) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } // create real-time emu connector _connector = new RealTimeEmulationTrader <IMessageAdapter>(new SmartComMessageAdapter(new MillisecondIncrementalIdGenerator()) { Login = Login.Text, Password = Password.Password.To <SecureString>(), Address = Address.SelectedAddress }); } else { // create real-time emu connector _connector = new RealTimeEmulationTrader <IMessageAdapter>(new IQFeedMarketDataMessageAdapter(new MillisecondIncrementalIdGenerator()) { Level1Address = Level1AddressCtrl.Text.To <EndPoint>(), Level2Address = Level2AddressCtrl.Text.To <EndPoint>(), LookupAddress = LookupAddressCtrl.Text.To <EndPoint>(), }); } SecurityEditor.SecurityProvider = new FilterableSecurityProvider(_connector); _candleManager = new CandleManager(_connector); _logManager.Sources.Add(_connector); // clear password for security reason //Password.Clear(); // subscribe on connection successfully event _connector.Connected += () => { // set flag (connection is established) _isConnected = true; // update gui labels this.GuiAsync(() => { ChangeConnectStatus(true); ConnectBtn.IsEnabled = false; }); }; // subscribe on connection error event _connector.ConnectionError += error => this.GuiAsync(() => { // update gui labels ChangeConnectStatus(false); MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2959); }); _connector.NewMarketDepths += OnDepths; _connector.MarketDepthsChanged += OnDepths; _connector.NewPortfolios += PortfolioGrid.Portfolios.AddRange; _connector.NewPositions += PortfolioGrid.Positions.AddRange; _connector.NewOrders += OrderGrid.Orders.AddRange; _connector.NewMyTrades += TradeGrid.Trades.AddRange; // subscribe on error of order registration event _connector.OrdersRegisterFailed += OrdersFailed; _candleManager.Processing += (s, candle) => { if (candle.State == CandleStates.Finished) { _buffer.Add(candle); } }; // subscribe on error event _connector.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // subscribe on error of market data subscription event _connector.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); } _connector.Connect(); } else { _connector.Disconnect(); } }
private void StartBtnClick(object sender, RoutedEventArgs e) { if (_connectors.Count > 0) { foreach (var connector in _connectors) { 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, }; if (FinamCandlesCheckBox.IsChecked == true) { _finamHistorySource.Refresh(new FinamSecurityStorage(security), security, s => {}, () => false); } // 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, HistorySource = d => _finamHistorySource.GetCandles(security, timeFrame, d.Date, d.Date), CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.FinamCandles }, FinamCandlesChart, FinamCandlesEquity, FinamCandlesPosition), Tuple.Create( YahooCandlesCheckBox, YahooCandlesProgress, YahooCandlesParameterGrid, // candles new EmulationInfo { UseCandleTimeFrame = timeFrame, HistorySource = d => new YahooHistorySource(_exchangeInfoProvider).GetCandles(security, timeFrame, d.Date, d.Date), CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.YahooCandles }, YahooCandlesChart, YahooCandlesEquity, YahooCandlesPosition), }; // storage to historical data var storageRegistry = new StorageRegistry { // set historical path DefaultDrive = new LocalMarketDataDrive(HistoryPath.Folder) }; var startTime = ((DateTime)From.Value).ChangeKind(DateTimeKind.Utc); var stopTime = ((DateTime)To.Value).ChangeKind(DateTimeKind.Utc); // (ru only) ОЛ необходимо загружать с 18.45 пред дня, чтобы стаканы строились правильно if (OrderLogCheckBox.IsChecked == true) { startTime = startTime.Subtract(TimeSpan.FromDays(1)).AddHours(18).AddMinutes(45).AddTicks(1).ApplyTimeZone(TimeHelper.Moscow).UtcDateTime; } // 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 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 : 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 var 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 = emulationInfo.UseCandleTimeFrame != null, CreateDepthFromOrdersLog = emulationInfo.UseOrderLog, CreateTradesFromOrdersLog = emulationInfo.UseOrderLog, HistoryMessageAdapter = { StorageRegistry = storageRegistry, // set history range StartDate = startTime, StopDate = stopTime, OrderLogMarketDepthBuilders = { { secId, LocalizedStrings.ActiveLanguage == Languages.Russian ? (IOrderLogMarketDepthBuilder) new PlazaOrderLogMarketDepthBuilder(secId) : new ItchOrderLogMarketDepthBuilder(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 candleManager = new CandleManager(connector); var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame) { BuildCandlesMode = emulationInfo.UseCandleTimeFrame == null ? BuildCandlesModes.Build : BuildCandlesModes.Load }; _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(chart, _candlesElem, _tradesElem, _shortMa, _shortElem, _longMa, _longElem, candleManager, 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.NewSecurity += s => { if (s != security) { return; } // fill level1 values connector.HistoryMessageAdapter.SendOutMessage(level1Info); if (emulationInfo.HistorySource != null) { if (emulationInfo.UseCandleTimeFrame != null) { connector.RegisterHistorySource(security, MarketDataTypes.CandleTimeFrame, emulationInfo.UseCandleTimeFrame.Value, emulationInfo.HistorySource); } if (emulationInfo.UseTicks) { connector.RegisterHistorySource(security, MarketDataTypes.Trades, null, emulationInfo.HistorySource); } if (emulationInfo.UseLevel1) { connector.RegisterHistorySource(security, MarketDataTypes.Level1, null, emulationInfo.HistorySource); } if (emulationInfo.UseMarketDepth) { connector.RegisterHistorySource(security, MarketDataTypes.MarketDepth, null, emulationInfo.HistorySource); } } else { 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); } if (emulationInfo.UseLevel1) { connector.RegisterSecurity(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 equity = set.Item6; var pnlCurve = equity.CreateCurve(LocalizedStrings.PnL + " " + emulationInfo.StrategyName, emulationInfo.CurveColor, LineChartStyles.Area); var unrealizedPnLCurve = equity.CreateCurve(LocalizedStrings.PnLUnreal + " " + emulationInfo.StrategyName, Colors.Black); var commissionCurve = equity.CreateCurve(LocalizedStrings.Str159 + " " + emulationInfo.StrategyName, Colors.Red, LineChartStyles.DashedLine); var posItems = set.Item7.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 ?? 0 }; 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(); 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 => { 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; }
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 ConnectClick(object sender, RoutedEventArgs e) { if (!_isConnected) { if (_connector == null) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } // создаем подключение _connector = new RealTimeEmulationTrader <Connector>(new SmartTrader { Login = Login.Text, Password = Password.Password, Address = Address.SelectedAddress }); //_trader = new RealTimeEmulationTrader<Connector>(new StockSharp.Plaza.PlazaTrader //{ // IsCGate = true, //}, portfolio); SecurityEditor.SecurityProvider = new FilterableSecurityProvider(_connector); _logManager.Sources.Add(_connector); // очищаем из текстового поля в целях безопасности //Password.Clear(); // подписываемся на событие успешного соединения _connector.Connected += () => { // возводим флаг, что соединение установлено _isConnected = true; // разблокируем кнопку Экспорт this.GuiAsync(() => ChangeConnectStatus(true)); _candleManager = new CandleManager(_connector); _connector.NewMarketDepths += OnDepths; _connector.MarketDepthsChanged += OnDepths; _connector.NewOrders += orders => Orders.Orders.AddRange(orders); _connector.NewMyTrades += trades => Trades.Trades.AddRange(trades); // подписываемся на событие о неудачной регистрации заявок _connector.OrdersRegisterFailed += OrdersFailed; _candleManager.Processing += (s, candle) => { if (candle.State == CandleStates.Finished) { _buffer.Add(candle); } }; _connector.StartExport(); this.GuiAsync(() => { ConnectBtn.IsEnabled = false; }); }; // подписываемся на событие разрыва соединения _connector.ConnectionError += error => this.GuiAsync(() => { // заблокируем кнопку Экспорт (так как соединение было потеряно) ChangeConnectStatus(false); MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2959); }); // подписываемся на ошибку обработки данных (транзакций и маркет) _connector.ProcessDataError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // подписываемся на ошибку подписки маркет-данных _connector.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); } _connector.Connect(); } else { _connector.Disconnect(); } }
private void ConnectClick(object sender, RoutedEventArgs e) { if (!_isConnected) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } if (_trader == null) { // создаем подключение _trader = new SmartTrader(); _logManager.Sources.Add(_trader); Portfolios.Portfolios = new PortfolioDataSource(_trader); // подписываемся на событие успешного соединения _trader.Connected += () => { // возводим флаг, что соединение установлено _isConnected = true; // разблокируем кнопку Экспорт this.GuiAsync(() => ChangeConnectStatus(true)); _candleManager = new CandleManager(_trader); _trader.NewCandles += (series, candles) => _historyCandles.SyncDo(col => { _historyCandles.AddRange(candles.Cast<TimeFrameCandle>()); foreach (var candle in candles) ProcessCandle(candle); }); _trader.NewSecurities += securities => { // находим нужную бумагу var lkoh = securities.FirstOrDefault(s => s.Code == "LKOH"); if (lkoh != null) { _lkoh = lkoh; this.GuiAsync(() => { Start.IsEnabled = true; }); } }; _trader.NewMyTrades += trades => { if (_strategy != null) { // найти те сделки, которые совершила стратегия скользящей средней trades = trades.Where(t => _strategy.Orders.Any(o => o == t.Order)); _trades.Trades.AddRange(trades); } }; // подписываемся на событие о неудачной регистрации заявок //_trader.OrdersRegisterFailed += OrdersFailed; _candleManager.Processing += (s, candle) => { // выводим только те свечи, которые не были отрисованы как исторические if (candle.OpenTime > _lastHistoryCandle) ProcessCandle(candle); }; this.GuiAsync(() => { ConnectBtn.IsEnabled = false; }); }; // подписываемся на событие разрыва соединения _trader.ConnectionError += error => this.GuiAsync(() => { // заблокируем кнопку Экспорт (так как соединение было потеряно) ChangeConnectStatus(false); MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2959); }); _trader.Disconnected += () => this.GuiAsync(() => ChangeConnectStatus(false)); // подписываемся на ошибку обработки данных (транзакций и маркет) //_trader.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), "Ошибка обработки данных")); // подписываемся на ошибку подписки маркет-данных _trader.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); } _trader.Login = Login.Text; _trader.Password = Password.Password; _trader.Address = Address.SelectedAddress; // очищаем из текстового поля в целях безопасности //Password.Clear(); _trader.Connect(); } else { _trader.Disconnect(); } }
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.Put(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 StartBtnClick(object sender, RoutedEventArgs e) { InitChart(); if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text)) { MessageBox.Show(this, LocalizedStrings.Str3014); return; } var secGen = new SecurityIdGenerator(); var secIdParts = secGen.Split(SecId.Text); var storageRegistry = new StorageRegistry() { DefaultDrive = new LocalMarketDataDrive(HistoryPath.Text) }; var startTime = ((DateTime)From.Value).ChangeKind(DateTimeKind.Utc); var stopTime = ((DateTime)To.Value).ChangeKind(DateTimeKind.Utc); //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 maxDepth = 5; var maxVolume = 5; var secCode = secIdParts.Item1; var board = ExchangeBoard.GetOrCreateBoard(secIdParts.Item2); var progressBar = TicksTestingProcess; var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>(); progressBar.Value = 0; progressBar.Maximum = 100; var statistic = TicksParameterGrid; var security = new Security() { Id = SecId.Text, Code = secCode, Board = board, }; var portfolio = new Portfolio() { Name = "test account", BeginValue = 1000000, }; var connector = new HistoryEmulationConnector(new[] { security }, new[] { portfolio }) { EmulationAdapter = { Emulator = { Settings = { MatchOnTouch = true, PortfolioRecalcInterval = TimeSpan.FromMilliseconds(100), SpreadSize = 1, }, LogLevel = LogLevels.Debug, }, LogLevel = LogLevels.Debug, }, HistoryMessageAdapter = { StorageRegistry = storageRegistry, StartDate = startTime, StopDate = stopTime, MarketTimeChangedInterval = TimeSpan.FromMilliseconds(50), }, }; //logManager.Sources.Add(connector); var candleManager = new CandleManager(connector); var series = new CandleSeries(typeof(RangeCandle), security, new Unit(100)); shortMa = new SimpleMovingAverage { Length = 10 }; shortElem = new ChartIndicatorElement { Color = Colors.Coral, ShowAxisMarker = false, FullTitle = shortMa.ToString() }; bufferedChart.AddElement(area, shortElem); longMa = new SimpleMovingAverage { Length = 30 }; longElem = new ChartIndicatorElement { ShowAxisMarker = false, FullTitle = longMa.ToString() }; bufferedChart.AddElement(area, longElem); var strategy = new SmaStrategy(bufferedChart, candlesElem, tradesElem, shortMa, shortElem, longMa, longElem, series) { Volume = 1, Portfolio = portfolio, Security = security, Connector = connector, LogLevel = LogLevels.Debug, UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>() }; //logManager.Sources.Add(strategy); connector.NewSecurities += securities => { if (securities.All(s => s != security)) { return; } connector.RegisterMarketDepth(security); connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security)) { Interval = TimeSpan.FromMilliseconds(100), // order book freq refresh is 1 sec MaxAsksDepth = maxDepth, MaxBidsDepth = maxDepth, UseTradeVolume = true, MaxVolume = maxVolume, MinSpreadStepCount = 1, // min spread generation is 2 pips MaxSpreadStepCount = 1, // max spread generation size (prevent extremely size) MaxPriceStepCount = 3 // pips size, }); connector.RegisterTrades(security); connector.RegisterSecurity(security); strategy.Start(); candleManager.Start(series); connector.Start(); }; statistic.Parameters.Clear(); statistic.Parameters.AddRange(strategy.StatisticManager.Parameters); var pnlCurve = Curve.CreateCurve(LocalizedStrings.PnL + " " + StrategyName, Colors.Cyan, EquityCurveChartStyles.Area); var unrealizedPnLCurve = Curve.CreateCurve(LocalizedStrings.PnLUnreal + StrategyName, Colors.Black); var commissionCurve = Curve.CreateCurve(LocalizedStrings.Str159 + " " + StrategyName, Colors.Red, EquityCurveChartStyles.DashedLine); var posItems = PositionCurve.CreateCurve(StrategyName, Colors.Crimson); 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; 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(); 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); } }; progressBar.Value = 0; startEmulationTime = DateTime.Now; connector.Connect(); connector.SendInMessage(new CommissionRuleMessage() { Rule = new CommissionPerTradeRule { Value = 0.01m } }); }
private void ConnectClick(object sender, RoutedEventArgs e) { if (!_isConnected) { if (_connector == null) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } // create real-time emu connector _connector = new RealTimeEmulationTrader <Connector>(new SmartTrader { Login = Login.Text, Password = Password.Password, Address = Address.SelectedAddress }); //_connector = new RealTimeEmulationTrader<Connector>(new PlazaTrader //{ // IsCGate = true, //}, portfolio); SecurityEditor.SecurityProvider = new FilterableSecurityProvider(_connector); _logManager.Sources.Add(_connector); // clear password for security reason //Password.Clear(); // subscribe on connection successfully event _connector.Connected += () => { // set flag (connection is established) _isConnected = true; // update gui labels this.GuiAsync(() => ChangeConnectStatus(true)); _candleManager = new CandleManager(_connector); _connector.NewMarketDepths += OnDepths; _connector.MarketDepthsChanged += OnDepths; _connector.NewOrders += orders => Orders.Orders.AddRange(orders); _connector.NewMyTrades += trades => Trades.Trades.AddRange(trades); // подписываемся на событие о неудачной регистрации заявок _connector.OrdersRegisterFailed += OrdersFailed; _candleManager.Processing += (s, candle) => { if (candle.State == CandleStates.Finished) { _buffer.Add(candle); } }; this.GuiAsync(() => { ConnectBtn.IsEnabled = false; }); }; // subscribe on connection error event _connector.ConnectionError += error => this.GuiAsync(() => { // update gui labels ChangeConnectStatus(false); MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2959); }); // subscribe on error event _connector.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // subscribe on error of market data subscription event _connector.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); } _connector.Connect(); } else { _connector.Disconnect(); } }
private void ConnectClick(object sender, RoutedEventArgs e) { var isLua = IsLua.IsChecked == true; if (isLua) { if (Address.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2977); return; } if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2978); return; } if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2979); return; } } else { if (Path.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2983); return; } } if (_trader == null) { // создаем подключение _trader = isLua ? new QuikTrader { LuaFixServerAddress = Address.Text.To<EndPoint>(), LuaLogin = Login.Text, LuaPassword = Password.Password.To<SecureString>() } : new QuikTrader(Path.Text) { IsDde = true }; if (_trader.IsDde) { _trader.DdeTables = new[] { _trader.SecuritiesTable, _trader.TradesTable }; } _logManager.Sources.Add(_trader); // подписываемся на событие об успешном восстановлении соединения _trader.Restored += () => this.GuiAsync(() => MessageBox.Show(this, LocalizedStrings.Str2958)); // подписываемся на событие разрыва соединения _trader.ConnectionError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString())); // подписываемся на ошибку обработки данных (транзакций и маркет) _trader.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), "Ошибка обработки данных")); // подписываемся на ошибку подписки маркет-данных _trader.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); _trader.NewSecurities += securities => this.GuiAsync(() => Security.ItemsSource = _trader.Securities); _trader.Connect(); _candleManager = new CandleManager(_trader); _candleManager.Processing += DrawCandle; ConnectBtn.IsEnabled = false; } }
private void ConnectClick(object sender, RoutedEventArgs e) { if (!_isConnected) { if (_connector == null) { if (SmartCom.IsChecked == true) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } // create real-time emu connector _connector = new RealTimeEmulationTrader<IMessageAdapter>(new SmartComMessageAdapter(new MillisecondIncrementalIdGenerator()) { Login = Login.Text, Password = Password.Password.To<SecureString>(), Address = Address.SelectedAddress }); _connector.EmulationAdapter.Emulator.Settings.TimeZone = TimeHelper.Moscow; } else { // create real-time emu connector _connector = new RealTimeEmulationTrader<IMessageAdapter>(new IQFeedMarketDataMessageAdapter(new MillisecondIncrementalIdGenerator()) { Level1Address = Level1AddressCtrl.Text.To<EndPoint>(), Level2Address = Level2AddressCtrl.Text.To<EndPoint>(), LookupAddress = LookupAddressCtrl.Text.To<EndPoint>(), }); _connector.EmulationAdapter.Emulator.Settings.TimeZone = TimeHelper.Est; } _connector.EmulationAdapter.Emulator.Settings.ConvertTime = true; SecurityEditor.SecurityProvider = new FilterableSecurityProvider(_connector); _candleManager = new CandleManager(_connector); _logManager.Sources.Add(_connector); // clear password for security reason //Password.Clear(); // subscribe on connection successfully event _connector.Connected += () => { // update gui labels this.GuiAsync(() => { ChangeConnectStatus(true); }); }; // subscribe on disconnection event _connector.Disconnected += () => { // update gui labels this.GuiAsync(() => { ChangeConnectStatus(false); }); }; // subscribe on connection error event _connector.ConnectionError += error => this.GuiAsync(() => { // update gui labels ChangeConnectStatus(false); MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2959); }); _connector.NewMarketDepths += OnDepths; _connector.MarketDepthsChanged += OnDepths; _connector.NewPortfolios += PortfolioGrid.Portfolios.AddRange; _connector.NewPositions += PortfolioGrid.Positions.AddRange; _connector.NewOrders += OrderGrid.Orders.AddRange; _connector.NewMyTrades += TradeGrid.Trades.AddRange; // subscribe on error of order registration event _connector.OrdersRegisterFailed += OrdersFailed; _candleManager.Processing += (s, candle) => { if (candle.State == CandleStates.Finished) _buffer.Add(candle); }; // subscribe on error event _connector.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // subscribe on error of market data subscription event _connector.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); } ConnectBtn.IsEnabled = false; _connector.Connect(); } else { _connector.Disconnect(); } }
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 } }); }
private void ConnectClick(object sender, RoutedEventArgs e) { if (!_isConnected) { if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2974); return; } else if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2975); return; } if (_trader == null) { // создаем подключение _trader = new SmartTrader(); _logManager.Sources.Add(_trader); Portfolios.Portfolios = new PortfolioDataSource(_trader); // подписываемся на событие успешного соединения _trader.Connected += () => { // возводим флаг, что соединение установлено _isConnected = true; // разблокируем кнопку Экспорт this.GuiAsync(() => ChangeConnectStatus(true)); _candleManager = new CandleManager(_trader); _trader.NewCandles += (series, candles) => _historyCandles.SyncDo(col => { _historyCandles.AddRange(candles.Cast <TimeFrameCandle>()); foreach (var candle in candles) { ProcessCandle(candle); } }); _trader.NewSecurities += securities => { // находим нужную бумагу var lkoh = securities.FirstOrDefault(s => s.Code == "LKOH"); if (lkoh != null) { _lkoh = lkoh; this.GuiAsync(() => { Start.IsEnabled = true; }); } }; _trader.NewMyTrades += trades => { if (_strategy != null) { // найти те сделки, которые совершила стратегия скользящей средней trades = trades.Where(t => _strategy.Orders.Any(o => o == t.Order)); _trades.Trades.AddRange(trades); } }; // подписываемся на событие о неудачной регистрации заявок //_trader.OrdersRegisterFailed += OrdersFailed; _candleManager.Processing += (s, candle) => { // выводим только те свечи, которые не были отрисованы как исторические if (candle.OpenTime > _lastHistoryCandle) { ProcessCandle(candle); } }; this.GuiAsync(() => { ConnectBtn.IsEnabled = false; }); }; // подписываемся на событие разрыва соединения _trader.ConnectionError += error => this.GuiAsync(() => { // заблокируем кнопку Экспорт (так как соединение было потеряно) ChangeConnectStatus(false); MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2959); }); _trader.Disconnected += () => this.GuiAsync(() => ChangeConnectStatus(false)); // подписываемся на ошибку обработки данных (транзакций и маркет) //_trader.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), "Ошибка обработки данных")); // подписываемся на ошибку подписки маркет-данных _trader.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); } _trader.Login = Login.Text; _trader.Password = Password.Password; _trader.Address = Address.SelectedAddress; // очищаем из текстового поля в целях безопасности //Password.Clear(); _trader.Connect(); } else { _trader.Disconnect(); } }
private void InitEmuConnector() { if (_emuConnector != null) { _emuConnector.Dispose(); _logManager.Sources.Remove(_emuConnector); } _emuConnector = new RealTimeEmulationTrader <IMessageAdapter>(_realConnector.MarketDataAdapter ?? new PassThroughMessageAdapter(new IncrementalIdGenerator()), _emuPf, false); _logManager.Sources.Add(_emuConnector); _emuConnector.EmulationAdapter.Emulator.Settings.TimeZone = TimeHelper.Est; _emuConnector.EmulationAdapter.Emulator.Settings.ConvertTime = true; SecurityPicker.SecurityProvider = new FilterableSecurityProvider(_emuConnector); SecurityPicker.MarketDataProvider = _emuConnector; _candleManager = new CandleManager(_emuConnector); // subscribe on connection successfully event _emuConnector.Connected += () => { // update gui labels this.GuiAsync(() => { ChangeConnectStatus(true); }); }; // subscribe on disconnection event _emuConnector.Disconnected += () => { // update gui labels this.GuiAsync(() => { ChangeConnectStatus(false); }); }; // subscribe on connection error event _emuConnector.ConnectionError += error => this.GuiAsync(() => { // update gui labels ChangeConnectStatus(false); MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2959); }); _emuConnector.NewMarketDepth += OnDepth; _emuConnector.MarketDepthChanged += OnDepth; _emuConnector.NewPortfolio += PortfolioGrid.Portfolios.Add; _emuConnector.NewPosition += PortfolioGrid.Positions.Add; _emuConnector.NewOrder += OrderGrid.Orders.Add; _emuConnector.NewMyTrade += TradeGrid.Trades.Add; // subscribe on error of order registration event _emuConnector.OrderRegisterFailed += OrderGrid.AddRegistrationFail; _candleManager.Processing += (s, candle) => { if (candle.State == CandleStates.Finished) { _buffer.Add(candle); } }; _emuConnector.MassOrderCancelFailed += (transId, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str716)); // subscribe on error event _emuConnector.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // subscribe on error of market data subscription event _emuConnector.MarketDataSubscriptionFailed += (security, msg, error) => { if (error == null) { return; } this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(msg.DataType, security))); }; }
private void InitConnector() { _connector?.Dispose(); try { if (File.Exists(_settingsFile)) { _realAdapter.Load(new XmlSerializer <SettingsStorage>().Deserialize(_settingsFile)); } _realAdapter.InnerAdapters.ForEach(a => a.RemoveTransactionalSupport()); } catch { } _connector = new RealTimeEmulationTrader <IMessageAdapter>(_realAdapter); _logManager.Sources.Add(_connector); _connector.EmulationAdapter.Emulator.Settings.TimeZone = TimeHelper.Est; _connector.EmulationAdapter.Emulator.Settings.ConvertTime = true; SecurityPicker.SecurityProvider = new FilterableSecurityProvider(_connector); SecurityPicker.MarketDataProvider = _connector; _candleManager = new CandleManager(_connector); _logManager.Sources.Add(_connector); // clear password for security reason //Password.Clear(); // subscribe on connection successfully event _connector.Connected += () => { // update gui labels this.GuiAsync(() => { ChangeConnectStatus(true); }); }; // subscribe on disconnection event _connector.Disconnected += () => { // update gui labels this.GuiAsync(() => { ChangeConnectStatus(false); }); }; // subscribe on connection error event _connector.ConnectionError += error => this.GuiAsync(() => { // update gui labels ChangeConnectStatus(false); MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2959); }); _connector.NewMarketDepth += OnDepth; _connector.MarketDepthChanged += OnDepth; _connector.NewPortfolio += PortfolioGrid.Portfolios.Add; _connector.NewPosition += PortfolioGrid.Positions.Add; _connector.NewOrder += OrderGrid.Orders.Add; _connector.NewMyTrade += TradeGrid.Trades.Add; // subscribe on error of order registration event _connector.OrderRegisterFailed += OrderGrid.AddRegistrationFail; _candleManager.Processing += (s, candle) => { if (candle.State == CandleStates.Finished) { _buffer.Add(candle); } }; _connector.MassOrderCancelFailed += (transId, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str716)); // subscribe on error event _connector.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2955)); // subscribe on error of market data subscription event _connector.MarketDataSubscriptionFailed += (security, msg, error) => { if (error == null) { return; } this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(msg.DataType, security))); }; }
static void Main(string[] args) { _handler = new AutoResetEvent(false); _connector = new QuikTrader(); // Создается andleManager, который будет использовать данные из коннектора _candleManager = new CandleManager(_connector); // Также можно создать СandleManager, который использует произвольную коллекцию данных. // В контексте этого примера этот способ следует использовать, когда получен инстумент и выполнена подписка на сделки // по инструменту //_candleManager = CreateCandleManager(_connector, _security); _connector.Connected += () => { Console.WriteLine("Соединение установлено!"); }; _connector.Disconnected += () => { Console.WriteLine("Соединение разорвано!"); Console.WriteLine("Для выхода нажмите Q и Enter."); }; _connector.NewSecurities += securities => { securities.ForEach(s => { if (s.Id == _securityId) { _security = s; _handler.Set(); } }); }; _candleManager.Processing += (series, candle) => { if (_series == null || _series != series) { return; } // Используем только завершенные свечи if (candle.State != CandleStates.Finished) { return; } if (candle.OpenTime < (DateTimeOffset.Now - TimeSpan.FromMinutes(6))) { // В эту ветку попадает исторические свечи, которые вычленяются при помощи текущего времени. // Обратите внимание, что из текущего времени вычитается тайм-фрейм свечи, увеличенный на 1 минуту //(чтобы учесть разность между локальным времемем и временем сервера).. // Debug.WriteLine(string.Format("История. {0}", candle)); } else { Debug.WriteLine(string.Format("Текущая. {0}", candle)); } }; _connector.Connect(); _handler.WaitOne(); // создаем серию _series = new CandleSeries(typeof(TimeFrameCandle), _security, TimeSpan.FromMinutes(5)); // стартуем серию _candleManager.Start(_series); Console.Read(); // останавливаем серию _candleManager.Stop(_series); _connector.Disconnect(); // Ждет, пока последовательно не будут нажаты клаваши Q и Enter, // после чего программа завершит работу while (Console.ReadLine().ToUpper() != "Q") { ; } }
private void ConnectClick(object sender, RoutedEventArgs e) { var isLua = IsLua.IsChecked == true; if (isLua) { if (Address.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2977); return; } if (Login.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2978); return; } if (Password.Password.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2979); return; } } else { if (QuikPath.Folder.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2983); return; } } if (_trader == null) { // создаем подключение _trader = isLua ? new QuikTrader { LuaFixServerAddress = Address.Text.To <EndPoint>(), LuaLogin = Login.Text, LuaPassword = Password.Password.To <SecureString>() } : new QuikTrader(QuikPath.Folder) { IsDde = true }; if (_trader.IsDde) { _trader.DdeTables = new[] { _trader.SecuritiesTable, _trader.TradesTable }; } _logManager.Sources.Add(_trader); // подписываемся на событие об успешном восстановлении соединения _trader.Restored += () => this.GuiAsync(() => MessageBox.Show(this, LocalizedStrings.Str2958)); // подписываемся на событие разрыва соединения _trader.ConnectionError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString())); // подписываемся на ошибку обработки данных (транзакций и маркет) _trader.Error += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), "Ошибка обработки данных")); // подписываемся на ошибку подписки маркет-данных _trader.MarketDataSubscriptionFailed += (security, type, error) => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), LocalizedStrings.Str2956Params.Put(type, security))); Security.SecurityProvider = new FilterableSecurityProvider(_trader); _trader.Connect(); _candleManager = new CandleManager(_trader); _candleManager.Processing += DrawCandle; ConnectBtn.IsEnabled = false; } }
private CandleManager CreateCandleManager() { var candleManager = new CandleManager(EmulationConnector); candleManager.Sources.RemoveWhere(s => s is StorageCandleSource); return candleManager; }
static void Main(string[] args) { var security = new Security() { Id = "RIH7@FORTS", Board = ExchangeBoard.Forts }; StorageRegistry storage = new StorageRegistry(); string path = @"../../../Data/Quik"; //Для работы будем использовать готовое локальное файловое хранилище, в которое данные были предварительно записаны при помощи Гидры. //Создаем экземпляр LocalMarketDataDrive. LocalMarketDataDrive drive = new LocalMarketDataDrive() { Path = path }; //Передаем в StorageRegistry ссылку на локальное файловое хранилище storage.DefaultDrive = drive; DateTime from = new DateTime(2017, 02, 14, 10, 0, 0); DateTime to = new DateTime(2017, 02, 15, 23, 50, 0); // Создаем простой индикатор - простая скользяшая средняя. Простой индикатор - индикатор, которые состоит из одного индикатора. var ma = new SimpleMovingAverage() { Length = 11 }; // Событие генерируется при изменении текущего значения индикатора.. Событие имеет два параметра: входное и выходное значение. ma.Changed += (input, output) => { //TODO }; // Создаем комплексный индикатор - полосы Боллинджера. Комплексный индикатор - индикатор, которые состоит из нескольких простых или комплексных // индикаторов. В состав полос Боллинджера входят три простых индикатора: верхняя и нижняя полоса BollingerBand, а также простая скользящая средняя. var bb = new BollingerBands() { Length = 11, Width = 1.5m }; // Событие генерируется при изменении текущего значения индикатора.. Событие имеет два параметра: входное и выходное значение. bb.Changed += (input, output) => { //TODO }; // Создаем кандлеменеджер, который в качестве источника свечек использует сделки из хранилища. CandleManager candleManager = new CandleManager(new TradeStorageCandleBuilderSource() { StorageRegistry = storage }); candleManager.Processing += (series, candle) => { if (candle.State != CandleStates.Finished) { return; } // передаем в метод Process значение для обработки... // Передаваемый параметр должен реализовывать интерфейс IIndicatorValue. // В нашем случае используется метод расширения, который преобразует // свечу в класс CandleIndicatorValue, который реализует требуемый интерфейс. // Функция возвращается тип, который также реализует интерфейс IIndicatorValue // Такой подход обладает следующими преимуществами: // 1. IIndicatorValue используется при построении графиков // 2. Значение одного индикторы, можно сразу передавать на вход другого индикатра. var maValue = ma.Process(candle); // Свойство IsFormed становится true, когда текущее значение индикатора становится валидным // Наример, в скользящих средних, если число значений поступивших на вход больше или равно // периоду индикатора if (ma.IsFormed) { // Так можно вернуть "нормальное" значение из IIndicatorValue var maCur = ma.GetCurrentValue(); // Это другой способ получения "нормальное" текущего значения индикатора maCur = maValue.GetValue <decimal>(); } // Здесь мы используем комплексный индикатор. Также передаем в метод Process значение для обработки... // На выходе мы получаем тип ComplexIndicatorValue (тоже реализует IIndicatorValue). // Главная особенность типа ComplexIndicatorValue в наличии свойства InnerValues, где // хранятся текущие значения всех простых индикаторов, входящих в состав комплексного индикатора. var bbValue = (ComplexIndicatorValue)bb.Process(candle); if (bb.IsFormed) { // Так можно получить значения из InnerValues var upBandValue = bbValue.InnerValues[bb.UpBand]; var lowBandValue = bbValue.InnerValues[bb.LowBand]; var upBand = bb.UpBand.GetCurrentValue(); var lowBand = bb.LowBand.GetCurrentValue(); upBand = upBandValue.GetValue <decimal>(); lowBand = lowBandValue.GetValue <decimal>(); } }; var srs = new CandleSeries(typeof(TimeFrameCandle), security, TimeSpan.FromMinutes(1)); candleManager.Start(srs, from, to); Console.Read(); candleManager.Stop(srs); }
private void ConnectClick(object sender, RoutedEventArgs e) { if (_trader == null || _trader.ConnectionState == ConnectionStates.Disconnected) { if (_trader == null) { if (Path.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2983); return; } // создаем подключение _trader = new QuikTrader(Path.Text) { IsDde = true }; Portfolios.Portfolios = new PortfolioDataSource(_trader); _trader.Connected += () => { _candleManager = new CandleManager(_trader); _trader.NewSecurities += securities => { // находим нужную бумагу var lkoh = securities.FirstOrDefault(s => s.Code == "LKOH"); if (lkoh != null) { _lkoh = lkoh; this.GuiAsync(() => { Start.IsEnabled = true; }); } }; _trader.NewMyTrades += trades => { if (_strategy != null) { // найти те сделки, которые совершила стратегия скользящей средней trades = trades.Where(t => _strategy.Orders.Any(o => o == t.Order)); Trades.Trades.AddRange(trades); } }; _candleManager.Processing += (series, candle) => { // если скользящие за сегодняшний день отрисованы, то рисуем в реальном времени текущие скользящие if (_isTodaySmaDrawn && candle.State == CandleStates.Finished) { ProcessCandle(candle); } }; //_trader.Error += ex => this.GuiAsync(() => MessageBox.Show(this, ex.ToString())); _trader.ConnectionError += ex => { if (ex != null) { this.GuiAsync(() => MessageBox.Show(this, ex.ToString())); } }; this.GuiAsync(() => { ConnectBtn.IsEnabled = false; Report.IsEnabled = true; }); }; } _trader.Connect(); } else { _trader.Disconnect(); } }
private void ConnectClick(object sender, RoutedEventArgs e) { if (_trader == null || _trader.ConnectionState == ConnectionStates.Disconnected) { if (_trader == null) { if (Path.Text.IsEmpty()) { MessageBox.Show(this, LocalizedStrings.Str2983); return; } // создаем подключение _trader = new QuikTrader(Path.Text) { IsDde = true }; Portfolios.Connector = _trader; _trader.Connected += () => { _candleManager = new CandleManager(_trader); _trader.NewSecurities += securities => { // находим нужную бумагу var lkoh = securities.FirstOrDefault(s => s.Code == "LKOH"); if (lkoh != null) { _lkoh = lkoh; this.GuiAsync(() => { Start.IsEnabled = true; }); } }; _trader.NewMyTrades += trades => { if (_strategy != null) { // найти те сделки, которые совершила стратегия скользящей средней trades = trades.Where(t => _strategy.Orders.Any(o => o == t.Order)); Trades.Trades.AddRange(trades); } }; _candleManager.Processing += (series, candle) => { // если скользящие за сегодняшний день отрисованы, то рисуем в реальном времени текущие скользящие if (_isTodaySmaDrawn && candle.State == CandleStates.Finished) ProcessCandle(candle); }; //_trader.Error += ex => this.GuiAsync(() => MessageBox.Show(this, ex.ToString())); _trader.ConnectionError += ex => { if (ex != null) this.GuiAsync(() => MessageBox.Show(this, ex.ToString())); }; this.GuiAsync(() => { ConnectBtn.IsEnabled = false; Report.IsEnabled = true; }); }; } _trader.Connect(); } else _trader.Disconnect(); }
public stockCandleManager(DBConnection DB, Stock stock) { this.stock = stock; candleManager = new CandleManager(DB); }
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"; }