private void CreateSourceElements(IndexSecurity security) { var area = _mainArea; var axisId = 1; foreach (var innerSecurity in security.InnerSecurities) { var axisName = "SA_" + axisId++; var series = new CandleSeries(typeof(TimeFrameCandle), innerSecurity, TimeSpan.FromMinutes(5)); var indicatorElement = new ChartIndicatorElement { Title = innerSecurity.Id, Color = _colors[axisId], YAxisId = axisName, StrokeThickness = 1 }; area.YAxises.Add(new ChartAxis { Id = axisName, AutoRange = true, AxisType = ChartAxisType.Numeric, AxisAlignment = ChartAxisAlignment.Right }); var indicator = new CandlePartIndicator(); //_indicators.Add(indicatorElement, indicator); _sourceElements.Add(innerSecurity, indicatorElement); _bufferedChart.AddElement(area, indicatorElement, series, indicator); } }
private void AddIndicator(ChartIndicatorElement element) { var series = (CandleSeries)_bufferedChart.GetSource(element); if (series == null) { return; } if (_sourceElements.ContainsKey(series.Security)) { return; } List <RefPair <DateTimeOffset, IDictionary <IChartElement, object> > > allValues; lock (_syncRoot) { allValues = series .GetCandles <TimeFrameCandle>() .Take(_candlesCount) .Select(candle => new RefPair <DateTimeOffset, IDictionary <IChartElement, object> >(candle.OpenTime, new Dictionary <IChartElement, object> { { element, CreateIndicatorValue(element, candle) } })) .ToList(); _skipElements.Remove(element); } _bufferedChart.Reset(new[] { element }); _bufferedChart.Draw(allValues); }
private void OnChartPanelSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { _bufferedChart.SetSource(element, candleSeries); _indicators.Add(element, indicator); AddElement(element, candleSeries); }
private void Chart_SubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator) { var candles = _candles.TryGetValue(series.Security); if (candles == null) { throw new InvalidOperationException("_candles == null"); } var values = candles .Select(candle => { if (candle.State != CandleStates.Finished) { candle.State = CandleStates.Finished; } return(new RefPair <DateTimeOffset, IDictionary <IChartElement, object> >(candle.OpenTime, new Dictionary <IChartElement, object> { { element, indicator.Process(candle) } })); }) .ToArray(); Chart.Draw(values); }
private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator) { _dataThreadActions.Add(() => { var oldReset = Chart.DisableIndicatorReset; try { Chart.DisableIndicatorReset = true; indicator.Reset(); } finally { Chart.DisableIndicatorReset = oldReset; } var chartData = new ChartDrawData(); foreach (var candle in _allCandles.CachedValues) { chartData.Group(candle.OpenTime).Add(element, indicator.Process(candle)); } Chart.Reset(new[] { element }); Chart.Draw(chartData); _indicators[element] = indicator; }); }
private void InitChart(CandleSeries series) { Chart.ClearAreas(); _area = new ChartArea(); var yAxis = _area.YAxises.First(); var xAxis = _area.XAxises.First(); yAxis.AutoRange = true; Chart.IsAutoRange = true; Chart.IsAutoScroll = true; Chart.ShowOverview = true; _sma = new SimpleMovingAverage() { Length = (int)IntegerUpDown.Value }; _candleElement = new ChartCandleElement() { FullTitle = "Candles" }; _indicatorElement = new ChartIndicatorElement() { FullTitle = "SMA" }; Chart.AddArea(_area); Chart.AddElement(_area, _candleElement, series); Chart.AddElement(_area, _indicatorElement); }
private void SetSource(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { RefPair <DateTimeOffset, IDictionary <IChartElement, object> >[] values = null; lock (_syncRoot) { _indicators[element] = indicator; var isNew = !_elementsBySeries.ContainsKey(candleSeries); if (!isNew && CanProcess) { values = ProcessHistoryCandles(element, candleSeries); } else if (isNew) { SubscribeSeries(candleSeries); } var lastDate = values == null || values.IsEmpty() ? DateTimeOffset.MinValue : values.Last().First; _elementsInfo.SafeAdd(element, e => RefTuple.Create(lastDate, candleSeries)); _elementsBySeries.SafeAdd(candleSeries).Add(element); } if (values != null && values.Length > 0) { new ChartDrawCommand(values).Process(this); } }
private void OnChartPanelSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { _drawTimer.Cancel(); _elements.Add(new RefPair<IChartElement, int>(element, 0)); _indicators.Add(element, indicator); _drawTimer.Activate(); }
private void OnChartPanelSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { _drawTimer.Cancel(); _elements.Add(new RefPair <IChartElement, int>(element, 0)); _indicators.Add(element, indicator); _drawTimer.Activate(); }
public UnSubscribeIndicatorElementCommand(ChartIndicatorElement element) { if (element == null) { throw new ArgumentNullException(nameof(element)); } Element = element; }
private IIndicatorValue CreateIndicatorValue(ChartIndicatorElement element, Candle candle) { var indicator = _indicators.TryGetValue(element); if (indicator == null) { throw new InvalidOperationException(LocalizedStrings.IndicatorNotFound.Put(element)); } return(indicator.Process(candle)); }
public SubscribeIndicatorElementCommand(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { if (element == null) throw new ArgumentNullException(nameof(element)); if (candleSeries == null) throw new ArgumentNullException(nameof(candleSeries)); if (indicator == null) throw new ArgumentNullException(nameof(indicator)); Element = element; CandleSeries = candleSeries; Indicator = indicator; }
private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator) { var chartData = new ChartDrawData(); foreach (var candle in _allCandles.Cache) { //if (candle.State != CandleStates.Finished) // candle.State = CandleStates.Finished; chartData.Group(candle.OpenTime).Add(element, indicator.Process(candle)); } Chart.Draw(chartData); _indicators.Add(element, indicator); }
public SmaStrategy(CandleSeries series, SimpleMovingAverage longSma, SimpleMovingAverage shortSma, IChart chart, ChartCandleElement candlesElem, ChartTradeElement tradesElem, ChartIndicatorElement longElem, ChartIndicatorElement shortElem) { _series = new Subscription(series); ShortSma = shortSma; LongSma = longSma; _chart = chart; _candlesElem = candlesElem; _tradesElem = tradesElem; _shortElem = shortElem; _longElem = longElem; }
public RiskStrategy(IChart chart, ChartCandleElement candlesElem, ChartTradeElement tradesElem, ChartIndicatorElement shortElem, ChartIndicatorElement longElem, CandleSeries series) { _chart = chart; _candlesElem = candlesElem; _tradesElem = tradesElem; _shortElem = shortElem; _longElem = longElem; _series = series; LongATR = (AverageTrueRange)longElem.Indicator; ShortATR = (AverageTrueRange)shortElem.Indicator; // PLB = new ParabolicSar(); }
private void ProcessIndicator(ChartIndicatorElement element, IEnumerable <Candle> candles) { var allValues = candles .Take(_candlesCount) .Select(candle => new RefPair <DateTimeOffset, IDictionary <IChartElement, object> >(candle.OpenTime, new Dictionary <IChartElement, object> { { element, CreateIndicatorValue(element, candle) } })) .ToList(); GuiDispatcher.GlobalDispatcher.AddAction(() => { ChartPanel.Reset(new[] { element }); ChartPanel.Draw(allValues); }); }
public SmaStrategy(IChart chart, ChartCandleElement candlesElem, ChartTradeElement tradesElem, SimpleMovingAverage shortMa, ChartIndicatorElement shortElem, SimpleMovingAverage longMa, ChartIndicatorElement longElem, CandleSeries series) { _chart = chart; _candlesElem = candlesElem; _tradesElem = tradesElem; _shortElem = shortElem; _longElem = longElem; _series = series; ShortSma = shortMa; LongSma = longMa; }
/// <summary> /// Инициализировать рендерер. /// </summary> /// <returns>Графические данные.</returns> public override IEnumerable <ChartIndicatorElement> Init() { InnerElements.Clear(); InnerElements.Add(_pnl = new ChartIndicatorElement { YAxisId = BaseElement.YAxisId, DrawStyle = ChartIndicatorDrawStyles.BandOneValue, Color = Colors.Green, AdditionalColor = Colors.Red, StrokeThickness = BaseElement.StrokeThickness, Title = "PnL" }); return(InnerElements); }
private void InitCharts() { Chart.ClearAreas(); _area = new ChartArea(); var yAxis = _area.YAxises.First(); yAxis.AutoRange = true; Chart.IsAutoRange = true; Chart.IsAutoScroll = true; Chart.AddArea(_area); var series = new CandleSeries( typeof(TimeFrameCandle), _security, TimeSpan.FromMinutes(_timeframe)); _indicatorElement = null; _candleElement = new ChartCandleElement { FullTitle = "Candles", YAxisId = yAxis.Id }; Chart.AddElement(_area, _candleElement, series); if (_addIndicator) { _indicator = new MyMovingAverage(200) { Name = "MyMA" }; _indicatorElement = new ChartIndicatorElement { DrawStyle = ChartIndicatorDrawStyles.Line, AntiAliasing = true, StrokeThickness = 1, Color = Colors.Blue, YAxisId = yAxis.Id, }; Chart.AddElement(_area, _indicatorElement, series, _indicator); } }
private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator, ChartPanel chart) { var values = _allCandles .Select(candle => { if (candle.State != CandleStates.Finished) candle.State = CandleStates.Finished; return new RefPair<DateTimeOffset, IDictionary<IChartElement, object>>(candle.OpenTime, new Dictionary<IChartElement, object> { { element, indicator.Process(candle) } }); }) .ToArray(); chart.Draw(values); }
public void Draw(CandleSeries series, IEnumerable <Candle> candles) { if (series == null) { throw new ArgumentNullException("series"); } if (candles == null) { throw new ArgumentNullException("candles"); } Series = series; _candles = candles; _candlesCount = 0; var ohlcArea = new ChartArea { Height = 210 }; ChartPanel.AddArea(ohlcArea); _candlesElem = new ChartCandleElement(); ChartPanel.AddElement(ohlcArea, _candlesElem, series); var volumeArea = new ChartArea { Height = 130 }; ChartPanel.AddArea(volumeArea); _volumeElem = new ChartIndicatorElement { IndicatorPainter = new VolumePainter(), }; var indicator = new VolumeIndicator(); _indicators.Add(_volumeElem, indicator); ChartPanel.AddElement(volumeArea, _volumeElem, series, indicator); CancelButton.Visibility = Visibility.Visible; _drawTimer.Flush(); }
private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator) { var values = _allCandles.Cache .Select(candle => { if (candle.State != CandleStates.Finished) { candle.State = CandleStates.Finished; } return(new RefPair <DateTimeOffset, IDictionary <IChartElement, object> >(candle.OpenTime, new Dictionary <IChartElement, object> { { element, indicator.Process(candle) } })); }); Chart.Draw(values); }
private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator) { _dataThreadActions.Add(() => { var chartData = new ChartDrawData(); foreach (var candle in _allCandles.CachedValues) { chartData.Group(candle.OpenTime).Add(element, indicator.Process(candle)); } Chart.Reset(new[] { element }); Chart.Draw(chartData); _indicators[element] = indicator; this.GuiAsync(() => CustomColors_Changed(null, null)); }); }
public SubscribeIndicatorElementCommand(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { if (element == null) { throw new ArgumentNullException(nameof(element)); } if (candleSeries == null) { throw new ArgumentNullException(nameof(candleSeries)); } if (indicator == null) { throw new ArgumentNullException(nameof(indicator)); } Element = element; CandleSeries = candleSeries; Indicator = indicator; }
private void CreateSourceElements(ContinuousSecurity security) { var area = _mainArea; var id = 1; foreach (var innerSecurity in security.InnerSecurities) { var series = new CandleSeries(typeof(TimeFrameCandle), innerSecurity, TimeSpan.FromMinutes(5)); var indicatorElement = new ChartIndicatorElement { Title = innerSecurity.Id, Color = _colors[id++], StrokeThickness = 1 }; var indicator = new CandlePartIndicator(); //_indicators.Add(indicatorElement, indicator); _sourceElements.Add(innerSecurity, indicatorElement); _bufferedChart.AddElement(area, indicatorElement, series, indicator); } }
private IIndicatorValue CreateIndicatorValue(ChartIndicatorElement element, Candle candle) { var indicator = _indicators.TryGetValue(element); if (indicator == null) throw new InvalidOperationException(LocalizedStrings.IndicatorNotFound.Put(element)); return indicator.Process(candle); }
private void StartClick(object sender, RoutedEventArgs e) { // если были получены и инструмент, и портфель if (_strategy == null) { if (Portfolios.SelectedPortfolio == null) { MessageBox.Show(this, LocalizedStrings.Str3009); return; } // создаем скользящие средние, на 80 5-минуток и 10 5-минуток var longSma = new SimpleMovingAverage { Length = 80 }; var shortSma = new SimpleMovingAverage { Length = 10 }; // регистрируем наш тайм-фрейм var series = new CandleSeries(typeof(TimeFrameCandle), _lkoh, _timeFrame); // создаем торговую стратегию _strategy = new SmaStrategy(_candleManager, series, longSma, shortSma) { Volume = 1, Security = _lkoh, Portfolio = Portfolios.SelectedPortfolio, Connector = _trader, }; _logManager.Sources.Add(_strategy); //_strategy.Log += OnLog; _strategy.PropertyChanged += OnStrategyPropertyChanged; _candlesElem = new ChartCandleElement(); _area.Elements.Add(_candlesElem); _longMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Long, Color = Colors.OrangeRed }; _area.Elements.Add(_longMaElem); _shortMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Short, Color = Colors.RoyalBlue }; _area.Elements.Add(_shortMaElem); var marketTime = _trader.CurrentTime; // начинаем получать свечи за период в 5 дней _candleManager.Start(series, DateTime.Today - TimeSpan.FromDays(5), marketTime); _lastHistoryCandle = _timeFrame.GetCandleBounds(marketTime).Min; Report.IsEnabled = true; } if (_strategy.ProcessState == ProcessStates.Stopped) { // запускаем процесс получения стакана, необходимый для работы алгоритма котирования _trader.RegisterMarketDepth(_strategy.Security); _strategy.Start(); Start.Content = LocalizedStrings.Str242; } else { _trader.UnRegisterMarketDepth(_strategy.Security); _strategy.Stop(); Start.Content = LocalizedStrings.Str2421; } }
private RefPair <DateTimeOffset, IDictionary <IChartElement, object> >[] ProcessHistoryCandles(ChartIndicatorElement element, CandleSeries series) { var candles = series.GetCandles <Candle>().Where(c => c.State == CandleStates.Finished).ToArray(); return(candles .Select(candle => new RefPair <DateTimeOffset, IDictionary <IChartElement, object> >(candle.OpenTime, new Dictionary <IChartElement, object> { { element, CreateIndicatorValue(element, candle) } })) .ToArray()); }
private List<RefPair<DateTimeOffset, IDictionary<IChartElement, object>>> ProcessHistoryCandles(ChartIndicatorElement element, CandleSeries series) { var candles = series.GetCandles<Candle>().Where(c => c.State == CandleStates.Finished).ToArray(); return candles .Select(candle => new RefPair<DateTimeOffset, IDictionary<IChartElement, object>>(candle.OpenTime, new Dictionary<IChartElement, object> { { element, CreateIndicatorValue(element, candle) } })) .ToList(); }
public void Draw(CandleSeries series, IEnumerable<Candle> candles) { if (series == null) throw new ArgumentNullException("series"); if (candles == null) throw new ArgumentNullException("candles"); Series = series; _candles = candles; //_candlesCount = 0; var ohlcArea = new ChartArea { Height = 210 }; ChartPanel.AddArea(ohlcArea); _candlesElem = new ChartCandleElement(); ChartPanel.AddElement(ohlcArea, _candlesElem, series); var volumeArea = new ChartArea { Height = 130 }; ChartPanel.AddArea(volumeArea); _volumeElem = new ChartIndicatorElement { IndicatorPainter = new VolumePainter(), }; var indicator = new VolumeIndicator(); ChartPanel.AddElement(volumeArea, _volumeElem, series, indicator); CancelButton.Visibility = Visibility.Visible; _drawTimer.Activate(); }
public UnSubscribeIndicatorElementCommand(ChartIndicatorElement element) { if (element == null) throw new ArgumentNullException(nameof(element)); Element = element; }
public override IEnumerable<ChartIndicatorElement> Init() { InnerElements.Clear(); InnerElements.Add(_pnl = new ChartIndicatorElement { YAxisId = BaseElement.YAxisId, DrawStyle = ChartIndicatorDrawStyles.BandOneValue, Color = Colors.Green, AdditionalColor = Colors.Red, StrokeThickness = BaseElement.StrokeThickness, Title = LocalizedStrings.PnL }); return InnerElements; }
private void StartClick(object sender, RoutedEventArgs e) { if (_strategy == null) { if (Portfolios.SelectedPortfolio == null) { MessageBox.Show(this, LocalizedStrings.Str3009); return; } // регистрируем наш тайм-фрейм var series = new CandleSeries(typeof(TimeFrameCandle), _lkoh, _timeFrame); // создаем торговую стратегию, скользящие средние на 80 5-минуток и 10 5-минуток _strategy = new SmaStrategy(_candleManager, series, new SimpleMovingAverage { Length = 80 }, new SimpleMovingAverage { Length = 10 }) { Volume = 1, Security = _lkoh, Portfolio = Portfolios.SelectedPortfolio, Connector = _trader, }; _strategy.Log += OnLog; _strategy.PropertyChanged += OnStrategyPropertyChanged; _candlesElem = new ChartCandleElement(); _area.Elements.Add(_candlesElem); _longMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Long, Color = Colors.OrangeRed }; _area.Elements.Add(_longMaElem); _shortMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Short, Color = Colors.RoyalBlue }; _area.Elements.Add(_shortMaElem); IEnumerable <Candle> candles = CultureInfo.InvariantCulture.DoInCulture(() => File.ReadAllLines("LKOH_history.txt").Select(line => { var parts = line.Split(','); var time = (parts[0] + parts[1]).ToDateTime("yyyyMMddHHmmss").ApplyTimeZone(TimeHelper.Moscow); return((Candle) new TimeFrameCandle { OpenPrice = parts[2].To <decimal>(), HighPrice = parts[3].To <decimal>(), LowPrice = parts[4].To <decimal>(), ClosePrice = parts[5].To <decimal>(), TimeFrame = _timeFrame, OpenTime = time, CloseTime = time + _timeFrame, TotalVolume = parts[6].To <decimal>(), Security = _lkoh, State = CandleStates.Finished, }); }).ToArray()); var lastCandleTime = default(DateTimeOffset); // начинаем вычислять скользящие средние foreach (var candle in candles) { ProcessCandle(candle); lastCandleTime = candle.OpenTime; } _candleManager.Start(series); // вычисляем временные отрезки текущей свечи var bounds = _timeFrame.GetCandleBounds(_trader.CurrentTime); candles = _candleManager.Container.GetCandles(series, new Range <DateTimeOffset>(lastCandleTime + _timeFrame, bounds.Min)); foreach (var candle in candles) { ProcessCandle(candle); } _isTodaySmaDrawn = true; Report.IsEnabled = true; } if (_strategy.ProcessState == ProcessStates.Stopped) { // запускаем процесс получения стакана, необходимый для работы алгоритма котирования _trader.RegisterMarketDepth(_strategy.Security); _strategy.Start(); Start.Content = LocalizedStrings.Str242; } else { _trader.UnRegisterMarketDepth(_strategy.Security); _strategy.Stop(); Start.Content = LocalizedStrings.Str2421; } }
private void OnChartPanelSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { new SubscribeIndicatorElementCommand(element, candleSeries, indicator).Process(this); }
private void OnChartPanelSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { _elements.Add(element); _indicators.Add(element, indicator); _drawTimer.Reset(); }
private void InitCharts() { Chart.ClearAreas(); _area = new ChartArea { ShowPerfStats = true }; var yAxis = _area.YAxises.First(); yAxis.AutoRange = true; Chart.IsAutoRange = true; Chart.IsAutoScroll = true; Chart.AddArea(_area); var series = new CandleSeries( typeof(TimeFrameCandle), _security, TimeSpan.FromMinutes(Timeframe)); _indicatorElement = null; _tradeElement = null; _candleElement = new ChartCandleElement(Timeframe, PriceStep) { FullTitle = "Candles", YAxisId = yAxis.Id }; Chart.AddElement(_area, _candleElement, series); if (AddIndicator) { _indicator = new MyMovingAverage(200) { Name = "MyMA" }; _indicatorElement = new ChartIndicatorElement { DrawStyle = ChartIndicatorDrawStyles.Line, Antialiasing = true, StrokeThickness = 1, Color = Colors.Blue, YAxisId = yAxis.Id, }; Chart.AddElement(_area, _indicatorElement, series, _indicator); } if (AddTrades) { _tradeElement = new ChartTradeElement { FullTitle = "Trades" }; Chart.AddElement(_area, _tradeElement, _security); } var ns = typeof(IIndicator).Namespace; var rendererTypes = typeof(Chart).Assembly .GetTypes() .Where(t => !t.IsAbstract && typeof(BaseChartIndicatorPainter).IsAssignableFrom(t)) .ToDictionary(t => t.Name); var indicators = typeof(IIndicator).Assembly .GetTypes() .Where(t => t.Namespace == ns && !t.IsAbstract && typeof(IIndicator).IsAssignableFrom(t)) .Select(t => { var name = t.Name; var p = rendererTypes.TryGetValue(name + "Painter"); if (p == null) { if (t.Name.EndsWith("Indicator")) { name = name.Substring(0, name.Length - "Indicator".Length); } p = rendererTypes.TryGetValue(name + "Painter"); } return(new IndicatorType(t, p)); }) .ToArray(); Chart.IndicatorTypes.AddRange(indicators); }
private void Chart_SubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator) { var candles = _candles.TryGetValue(series.Security); if (candles == null) throw new InvalidOperationException("_candles == null"); var values = candles .Select(candle => { if (candle.State != CandleStates.Finished) candle.State = CandleStates.Finished; return new RefPair<DateTimeOffset, IDictionary<IChartElement, object>>(candle.OpenTime, new Dictionary<IChartElement, object> { { element, indicator.Process(candle) } }); }) .ToArray(); Chart.Draw(values); }
private void AddIndicator(ChartIndicatorElement element) { var series = (CandleSeries)_bufferedChart.GetSource(element); if (series == null) return; if (_sourceElements.ContainsKey(series.Security)) return; IEnumerable<RefPair<DateTimeOffset, IDictionary<IChartElement, object>>> allValues; lock (_syncRoot) { allValues = series .GetCandles<TimeFrameCandle>() .Take(_candlesCount) .Select(candle => new RefPair<DateTimeOffset, IDictionary<IChartElement, object>>(candle.OpenTime, new Dictionary<IChartElement, object> { { element, CreateIndicatorValue(element, candle) } })) .ToArray(); _skipElements.Remove(element); } _bufferedChart.Reset(new[] { element }); _bufferedChart.Draw(allValues); }
private void Download_OnClick(object sender, RoutedEventArgs e) { var year = SelectedYear; var from = From.Value ?? year.Days.First(); var to = (To.Value ?? year.Days.Last()).EndOfDay(); var trader = SelectedTrader; var tf = SelectedTimeFrame; var seriesSet = _securityCtrls .Where(pair => pair.Key.SelectedSecurity != null) .Select(pair => Tuple.Create(new CandleSeries(typeof(TimeFrameCandle), pair.Key.SelectedSecurity, tf), pair.Value)) .ToArray(); BusyIndicator.BusyContent = "Подготовка данных..."; BusyIndicator.IsBusy = true; _candles.Clear(); var trades = new Dictionary<Security, Dictionary<DateTimeOffset, Tuple<MyTrade[], MyTrade>>>(); var worker = new BackgroundWorker { WorkerReportsProgress = true }; worker.DoWork += (o, ea) => { foreach (var series in seriesSet) { var security = series.Item1.Security; var candleStorage = _dataRegistry.GetCandleStorage(series.Item1, format: StorageFormats.Csv); var secCandles = _candles.SafeAdd(security); secCandles.Clear(); secCandles.AddRange(candleStorage.Load(from, to)); var candlesDatesCache = _candlesDates.SafeAdd(Tuple.Create(security, tf), k => new DatesCache(Path.Combine(((LocalMarketDataDrive)candleStorage.Drive.Drive).GetSecurityPath(security.ToSecurityId()), "{0}min_date.bin".Put((int)tf.TotalMinutes)))); var minCandleDate = candlesDatesCache.MinValue; var maxCandleDate = candlesDatesCache.MaxValue; if (from >= minCandleDate && to <= maxCandleDate) continue; var finamFrom = from; var finamTo = to; if (maxCandleDate != null && finamFrom >= minCandleDate && finamFrom <= maxCandleDate) finamFrom = maxCandleDate.Value + TimeSpan.FromDays(1); if (minCandleDate != null && finamTo >= minCandleDate && finamTo <= maxCandleDate) finamTo = minCandleDate.Value - TimeSpan.FromDays(1); if (finamTo <= finamFrom) continue; worker.ReportProgress(1, Tuple.Create(security, finamFrom, finamTo)); var newCandles = (tf.Ticks == 1 ? finamFrom.Range(finamTo, TimeSpan.FromDays(1)).SelectMany(day => _finamHistorySource.GetTrades(security, day, day)).ToEx().ToCandles<TimeFrameCandle>(tf) : _finamHistorySource.GetCandles(security, tf, finamFrom, finamTo) ).ToArray(); candleStorage.Save(newCandles); foreach (var date in newCandles.Select(c => c.OpenTime.Date).Distinct()) candlesDatesCache.Add(date); candlesDatesCache.Save(); // TODO secCandles.AddRange(newCandles); } var traderDrive = new LocalMarketDataDrive(trader); var traderStorage = _traderStorages.SafeAdd(trader, key => new StorageRegistry { DefaultDrive = traderDrive }); foreach (var series in seriesSet) { var security = series.Item1.Security; var olStorage = traderStorage.GetOrderLogStorage(security, format: StorageFormats.Csv); var tradeDatesCache = _tradesDates.SafeAdd(trader, k => new DatesCache(Path.Combine(traderDrive.Path, "dates.bin"))); var secTrades = from .Range(to, TimeSpan.FromDays(1)) .Intersect(year.Days) .SelectMany(date => { if (olStorage.Dates.Contains(date)) return olStorage.Load(date); if (tradeDatesCache.Contains(date)) return Enumerable.Empty<OrderLogItem>(); worker.ReportProgress(2, date); var loadedTrades = year.GetTrades(_securityStorage, trader, date); var dateTrades = Enumerable.Empty<OrderLogItem>(); foreach (var group in loadedTrades.GroupBy(t => t.Order.Security)) { var sec = group.Key; traderStorage .GetOrderLogStorage(sec, format: StorageFormats.Csv) .Save(group.OrderBy(i => i.Order.Time)); if (group.Key == security) dateTrades = group; } tradeDatesCache.Add(date); tradeDatesCache.Save(); return dateTrades; }) .GroupBy(ol => { var time = ol.Order.Time; var period = security.Board.WorkingTime.GetPeriod(time.ToLocalTime(security.Board.Exchange.TimeZoneInfo)); if (period != null && period.Times.Length > 0) { var last = period.Times.Last().Max; if (time.TimeOfDay >= last) time = time.AddTicks(-1); } return time.Truncate(tf); }) .ToDictionary(g => g.Key, g => { var candleTrades = g.Select(ol => new MyTrade { Order = ol.Order, Trade = ol.Trade }) .ToArray(); if (candleTrades.Length == 0) return null; var order = candleTrades[0].Order; var volume = candleTrades.Sum(t1 => t1.Trade.Volume * (t1.Order.Direction == Sides.Buy ? 1 : -1)); if (volume == 0) return Tuple.Create(candleTrades, (MyTrade)null); var side = volume > 0 ? Sides.Buy : Sides.Sell; volume = volume.Abs(); var availableVolume = volume; var avgPrice = 0m; foreach (var trade in candleTrades.Where(t1 => t1.Order.Direction == side)) { var tradeVol = trade.Trade.Volume.Min(availableVolume); avgPrice += trade.Trade.Price * tradeVol; availableVolume -= tradeVol; if (availableVolume <= 0) break; } avgPrice = avgPrice / volume; return Tuple.Create(candleTrades, new MyTrade { Order = new Order { Security = order.Security, Direction = side, Time = g.Key, Portfolio = order.Portfolio, Price = avgPrice, Volume = volume, }, Trade = new Trade { Security = order.Security, Time = g.Key, Volume = volume, Price = avgPrice } }); }); trades.Add(security, secTrades); } }; worker.ProgressChanged += (o, ea) => { switch (ea.ProgressPercentage) { case 1: BusyIndicator.BusyContent = "Скачивание {Item1.Id} свечей с {Item2:yyyy-MM-dd} по {Item3:yyyy-MM-dd}...".PutEx(ea.UserState); break; default: BusyIndicator.BusyContent = "Скачивание сделок за {0:yyyy-MM-dd}...".Put(ea.UserState); break; } }; worker.RunWorkerCompleted += (o, ea) => { BusyIndicator.IsBusy = false; if (ea.Error == null) { Chart.ClearAreas(); _statisticManager.Reset(); var candlesArea = new ChartArea(); Chart.AddArea(candlesArea); var positionArea = new ChartArea { Height = 200 }; Chart.AddArea(positionArea); positionArea.YAxises.Clear(); const string equityYAxis = "Equity"; candlesArea.YAxises.Clear(); candlesArea.YAxises.Add(new ChartAxis { Id = equityYAxis, AutoRange = true, AxisType = ChartAxisType.Numeric, AxisAlignment = ChartAxisAlignment.Left, }); var equityElem = new ChartIndicatorElement { YAxisId = equityYAxis, FullTitle = LocalizedStrings.PnL, IndicatorPainter = new PnlPainter() }; var equityInd = new SimpleMovingAverage { Length = 1 }; Chart.AddElement(candlesArea, equityElem); var chartValues = new SortedDictionary<DateTimeOffset, IDictionary<IChartElement, object>>(); var pnlValues = new Dictionary<DateTimeOffset, decimal>(); foreach (var series in seriesSet) { var security = series.Item1.Security; var candleYAxis = "Candles_Y_" + security.Id; candlesArea.YAxises.Add(new ChartAxis { Id = candleYAxis, AutoRange = true, AxisType = ChartAxisType.Numeric, AxisAlignment = ChartAxisAlignment.Right, }); var candlesElem = new ChartCandleElement { ShowAxisMarker = false, YAxisId = candleYAxis, }; Chart.AddElement(candlesArea, candlesElem, series.Item1); var tradesElem = new ChartTradeElement { BuyStrokeColor = Colors.Black, SellStrokeColor = Colors.Black, BuyColor = series.Item2.Buy, SellColor = series.Item2.Sell, FullTitle = LocalizedStrings.Str985 + " " + security.Id, YAxisId = candleYAxis, }; Chart.AddElement(candlesArea, tradesElem); var posYAxis = "Pos_Y_" + security.Id; positionArea.YAxises.Add(new ChartAxis { Id = posYAxis, AutoRange = true, AxisType = ChartAxisType.Numeric, AxisAlignment = ChartAxisAlignment.Right, }); var positionElem = new ChartIndicatorElement { FullTitle = LocalizedStrings.Str862 + " " + security.Id, YAxisId = posYAxis, Color = series.Item2.Position }; var positionInd = new SimpleMovingAverage { Length = 1 }; Chart.AddElement(positionArea, positionElem); var pnlQueue = new PnLQueue(security.ToSecurityId()); //var level1Info = new Level1ChangeMessage //{ // SecurityId = pnlQueue.SecurityId, //} //.TryAdd(Level1Fields.PriceStep, security.PriceStep) //.TryAdd(Level1Fields.StepPrice, security.StepPrice); //pnlQueue.ProcessLevel1(level1Info); var pos = 0m; var secTrades = trades[security]; var secValues = _candles[security] .Select(c => { if (c.State != CandleStates.Finished) c.State = CandleStates.Finished; pnlQueue.ProcessLevel1(new Level1ChangeMessage { SecurityId = security.ToSecurityId(), }.TryAdd(Level1Fields.LastTradePrice, c.ClosePrice)); var values = new Dictionary<IChartElement, object> { { candlesElem, c }, }; var candleTrade = secTrades.TryGetValue(c.OpenTime); if (candleTrade != null) { if (candleTrade.Item2 != null) values.Add(tradesElem, candleTrade.Item2); foreach (var myTrade in candleTrade.Item1) { pos += myTrade.Order.Direction == Sides.Buy ? myTrade.Trade.Volume : -myTrade.Trade.Volume; var pnl = pnlQueue.Process(myTrade.ToMessage()); _statisticManager.AddMyTrade(pnl); } _statisticManager.AddPosition(c.OpenTime, pos); _statisticManager.AddPnL(c.OpenTime, pnlQueue.RealizedPnL + pnlQueue.UnrealizedPnL); } pnlValues[c.OpenTime] = pnlValues.TryGetValue(c.OpenTime) + (pnlQueue.RealizedPnL + pnlQueue.UnrealizedPnL); values.Add(positionElem, positionInd.Process(pos)); return new RefPair<DateTimeOffset, IDictionary<IChartElement, object>> { First = c.OpenTime, Second = values }; }) .ToArray(); foreach (var pair in secValues) { var dict = chartValues.SafeAdd(pair.First, key => new Dictionary<IChartElement, object>()); foreach (var pair2 in pair.Second) { dict[pair2.Key] = pair2.Value; } } } foreach (var pair in pnlValues) { chartValues[pair.Key].Add(equityElem, equityInd.Process(pair.Value)); } Chart.IsAutoRange = true; try { Chart.Draw(chartValues.Select(p => RefTuple.Create(p.Key, p.Value))); } finally { Chart.IsAutoRange = false; } } else { new MessageBoxBuilder() .Error() .Owner(this) .Text(ea.Error.ToString()) .Show(); } }; worker.RunWorkerAsync(); }
private void StartBtnClick(object sender, RoutedEventArgs e) { InitChart(); if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text)) { MessageBox.Show(this, LocalizedStrings.Str3014); return; } if (_connectors.Any(t => t.State != EmulationStates.Stopped)) { MessageBox.Show(this, LocalizedStrings.Str3015); return; } var secIdParts = SecId.Text.Split('@'); if (secIdParts.Length != 2) { MessageBox.Show(this, LocalizedStrings.Str3016); return; } var timeFrame = TimeSpan.FromMinutes(5); // create backtesting modes var settings = new[] { Tuple.Create( TicksCheckBox, TicksTestingProcess, TicksParameterGrid, // ticks new EmulationInfo {UseTicks = true, CurveColor = Colors.DarkGreen, StrategyName = LocalizedStrings.Ticks}), Tuple.Create( TicksAndDepthsCheckBox, TicksAndDepthsTestingProcess, TicksAndDepthsParameterGrid, // ticks + order book new EmulationInfo {UseTicks = true, UseMarketDepth = true, CurveColor = Colors.Red, StrategyName = LocalizedStrings.XamlStr757}), Tuple.Create( DepthsCheckBox, DepthsTestingProcess, DepthsParameterGrid, // order book new EmulationInfo {UseMarketDepth = true, CurveColor = Colors.OrangeRed, StrategyName = LocalizedStrings.MarketDepths}), Tuple.Create( CandlesCheckBox, CandlesTestingProcess, CandlesParameterGrid, // candles new EmulationInfo {UseCandleTimeFrame = timeFrame, CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.Candles}), Tuple.Create( CandlesAndDepthsCheckBox, CandlesAndDepthsTestingProcess, CandlesAndDepthsParameterGrid, // candles + orderbook new EmulationInfo {UseMarketDepth = true, UseCandleTimeFrame = timeFrame, CurveColor = Colors.Cyan, StrategyName = LocalizedStrings.XamlStr635}), Tuple.Create( OrderLogCheckBox, OrderLogTestingProcess, OrderLogParameterGrid, // order log new EmulationInfo {UseOrderLog = true, CurveColor = Colors.CornflowerBlue, StrategyName = LocalizedStrings.OrderLog}) }; // storage to historical data var storageRegistry = new StorageRegistry { // set historical path DefaultDrive = new LocalMarketDataDrive(HistoryPath.Text) }; var startTime = ((DateTime)From.Value).ChangeKind(DateTimeKind.Utc); var stopTime = ((DateTime)To.Value).ChangeKind(DateTimeKind.Utc); // ОЛ необходимо загружать с 18.45 пред дня, чтобы стаканы строились правильно if (OrderLogCheckBox.IsChecked == true) startTime = startTime.Subtract(TimeSpan.FromDays(1)).AddHours(18).AddMinutes(45).AddTicks(1); // ProgressBar refresh step var progressStep = ((stopTime - startTime).Ticks / 100).To<TimeSpan>(); // set ProgressBar bounds _progressBars.ForEach(p => { p.Value = 0; p.Maximum = 100; }); var logManager = new LogManager(); var fileLogListener = new FileLogListener("sample.log"); logManager.Listeners.Add(fileLogListener); //logManager.Listeners.Add(new DebugLogListener()); // for track logs in output window in Vusial Studio (poor performance). var generateDepths = GenDepthsCheckBox.IsChecked == true; var maxDepth = MaxDepth.Text.To<int>(); var maxVolume = MaxVolume.Text.To<int>(); var secCode = secIdParts[0]; var board = ExchangeBoard.GetOrCreateBoard(secIdParts[1]); foreach (var set in settings) { if (set.Item1.IsChecked == false) continue; var progressBar = set.Item2; var statistic = set.Item3; var emulationInfo = set.Item4; // create test security var security = new Security { Id = SecId.Text, // sec id has the same name as folder with historical data Code = secCode, Board = board, }; var level1Info = new Level1ChangeMessage { SecurityId = security.ToSecurityId(), ServerTime = startTime, } .TryAdd(Level1Fields.PriceStep, 10m) .TryAdd(Level1Fields.StepPrice, 6m) .TryAdd(Level1Fields.MinPrice, 10m) .TryAdd(Level1Fields.MaxPrice, 1000000m) .TryAdd(Level1Fields.MarginBuy, 10000m) .TryAdd(Level1Fields.MarginSell, 10000m); // test portfolio var portfolio = new Portfolio { Name = "test account", BeginValue = 1000000, }; // create backtesting connector var connector = new HistoryEmulationConnector( new[] { security }, new[] { portfolio }) { MarketEmulator = { Settings = { // match order if historical price touched our limit order price. // It is terned off, and price should go through limit order price level // (more "severe" test mode) MatchOnTouch = false, } }, UseExternalCandleSource = emulationInfo.UseCandleTimeFrame != null, CreateDepthFromOrdersLog = emulationInfo.UseOrderLog, CreateTradesFromOrdersLog = emulationInfo.UseOrderLog, HistoryMessageAdapter = { StorageRegistry = storageRegistry, // set history range StartDate = startTime, StopDate = stopTime, }, // set market time freq as time frame MarketTimeChangedInterval = timeFrame, }; ((ILogSource)connector).LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info; logManager.Sources.Add(connector); var candleManager = emulationInfo.UseCandleTimeFrame == null ? new CandleManager(new TradeCandleBuilderSourceEx(connector)) : new CandleManager(connector); var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame); _shortMa = new SimpleMovingAverage { Length = 10 }; _shortElem = new ChartIndicatorElement { Color = Colors.Coral, ShowAxisMarker = false, FullTitle = _shortMa.ToString() }; _bufferedChart.AddElement(_area, _shortElem); _longMa = new SimpleMovingAverage { Length = 80 }; _longElem = new ChartIndicatorElement { ShowAxisMarker = false, FullTitle = _longMa.ToString() }; _bufferedChart.AddElement(_area, _longElem); // create strategy based on 80 5-min и 10 5-min var strategy = new SmaStrategy(_bufferedChart, _candlesElem, _tradesElem, _shortMa, _shortElem, _longMa, _longElem, series) { Volume = 1, Portfolio = portfolio, Security = security, Connector = connector, LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info, // by default interval is 1 min, // it is excessively for time range with several months UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To<TimeSpan>() }; logManager.Sources.Add(strategy); connector.NewSecurities += securities => { if (securities.All(s => s != security)) return; // fill level1 values connector.SendInMessage(level1Info); if (emulationInfo.UseMarketDepth) { connector.RegisterMarketDepth(security); if ( // if order book will be generated generateDepths || // of backtesting will be on candles emulationInfo.UseCandleTimeFrame != TimeSpan.Zero ) { // if no have order book historical data, but strategy is required, // use generator based on last prices connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security)) { Interval = TimeSpan.FromSeconds(1), // order book freq refresh is 1 sec MaxAsksDepth = maxDepth, MaxBidsDepth = maxDepth, UseTradeVolume = true, MaxVolume = maxVolume, MinSpreadStepCount = 2, // min spread generation is 2 pips MaxSpreadStepCount = 5, // max spread generation size (prevent extremely size) MaxPriceStepCount = 3 // pips size, }); } } if (emulationInfo.UseOrderLog) { connector.RegisterOrderLog(security); } if (emulationInfo.UseTicks) { connector.RegisterTrades(security); } // start strategy before emulation started strategy.Start(); candleManager.Start(series); // start historical data loading when connection established successfully and all data subscribed connector.Start(); }; // fill parameters panel statistic.Parameters.Clear(); statistic.Parameters.AddRange(strategy.StatisticManager.Parameters); var pnlCurve = Curve.CreateCurve("P&L " + emulationInfo.StrategyName, emulationInfo.CurveColor, EquityCurveChartStyles.Area); var unrealizedPnLCurve = Curve.CreateCurve(LocalizedStrings.PnLUnreal + emulationInfo.StrategyName, Colors.Black); var commissionCurve = Curve.CreateCurve(LocalizedStrings.Str159 + " " + emulationInfo.StrategyName, Colors.Red, EquityCurveChartStyles.DashedLine); var posItems = PositionCurve.CreateCurve(emulationInfo.StrategyName, emulationInfo.CurveColor); strategy.PnLChanged += () => { var pnl = new EquityData { Time = strategy.CurrentTime, Value = strategy.PnL - strategy.Commission ?? 0 }; var unrealizedPnL = new EquityData { Time = strategy.CurrentTime, Value = strategy.PnLManager.UnrealizedPnL }; var commission = new EquityData { Time = strategy.CurrentTime, Value = strategy.Commission ?? 0 }; pnlCurve.Add(pnl); unrealizedPnLCurve.Add(unrealizedPnL); commissionCurve.Add(commission); }; strategy.PositionChanged += () => posItems.Add(new EquityData { Time = strategy.CurrentTime, Value = strategy.Position }); var nextTime = startTime + progressStep; // handle historical time for update ProgressBar connector.MarketTimeChanged += d => { if (connector.CurrentTime < nextTime && connector.CurrentTime < stopTime) return; var steps = (connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1; nextTime = startTime + (steps * progressStep.Ticks).To<TimeSpan>(); this.GuiAsync(() => progressBar.Value = steps); }; connector.StateChanged += () => { if (connector.State == EmulationStates.Stopped) { candleManager.Stop(series); strategy.Stop(); logManager.Dispose(); _connectors.Clear(); SetIsEnabled(false); this.GuiAsync(() => { if (connector.IsFinished) { progressBar.Value = progressBar.Maximum; MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime)); } else MessageBox.Show(this, LocalizedStrings.cancelled); }); } else if (connector.State == EmulationStates.Started) { SetIsEnabled(true); } }; if (ShowDepth.IsChecked == true) { MarketDepth.UpdateFormat(security); connector.NewMessage += message => { var quoteMsg = message as QuoteChangeMessage; if (quoteMsg != null) MarketDepth.UpdateDepth(quoteMsg); }; } _connectors.Add(connector); progressBar.Value = 0; } _startEmulationTime = DateTime.Now; // start emulation foreach (var connector in _connectors) { // raise NewSecurities and NewPortfolio for full fill strategy properties connector.Connect(); // 1 cent commission for trade connector.SendInMessage(new CommissionRuleMessage { Rule = new CommissionPerTradeRule { Value = 0.01m } }); } TabControl.Items.Cast<TabItem>().First(i => i.Visibility == Visibility.Visible).IsSelected = true; }
private void StartClick(object sender, RoutedEventArgs e) { if (_strategy == null) { if (Portfolios.SelectedPortfolio == null) { MessageBox.Show(this, LocalizedStrings.Str3009); return; } // регистрируем наш тайм-фрейм var series = new CandleSeries(typeof(TimeFrameCandle), _lkoh, _timeFrame); // создаем торговую стратегию, скользящие средние на 80 5-минуток и 10 5-минуток _strategy = new SmaStrategy(series, new SimpleMovingAverage { Length = 80 }, new SimpleMovingAverage { Length = 10 }) { Volume = 1, Security = _lkoh, Portfolio = Portfolios.SelectedPortfolio, Connector = _trader, }; _strategy.Log += OnLog; _strategy.PropertyChanged += OnStrategyPropertyChanged; _candlesElem = new ChartCandleElement(); _area.Elements.Add(_candlesElem); _longMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Long, Color = Colors.OrangeRed }; _area.Elements.Add(_longMaElem); _shortMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Short, Color = Colors.RoyalBlue }; _area.Elements.Add(_shortMaElem); IEnumerable<Candle> candles = CultureInfo.InvariantCulture.DoInCulture(() => File.ReadAllLines("LKOH_history.txt").Select(line => { var parts = line.Split(','); var time = (parts[0] + parts[1]).ToDateTime("yyyyMMddHHmmss").ApplyTimeZone(TimeHelper.Moscow); return (Candle)new TimeFrameCandle { OpenPrice = parts[2].To<decimal>(), HighPrice = parts[3].To<decimal>(), LowPrice = parts[4].To<decimal>(), ClosePrice = parts[5].To<decimal>(), TimeFrame = _timeFrame, OpenTime = time, CloseTime = time + _timeFrame, TotalVolume = parts[6].To<decimal>(), Security = _lkoh, State = CandleStates.Finished, }; }).ToArray()); var lastCandleTime = default(DateTimeOffset); // начинаем вычислять скользящие средние foreach (var candle in candles) { ProcessCandle(candle); lastCandleTime = candle.OpenTime; } _candleManager.Start(series); // вычисляем временные отрезки текущей свечи var bounds = _timeFrame.GetCandleBounds(series.Security.ToExchangeTime(_trader.CurrentTime)); candles = _candleManager.Container.GetCandles(series, new Range<DateTimeOffset>(lastCandleTime + _timeFrame, bounds.Min)); foreach (var candle in candles) { ProcessCandle(candle); } _isTodaySmaDrawn = true; Report.IsEnabled = true; } if (_strategy.ProcessState == ProcessStates.Stopped) { // запускаем процесс получения стакана, необходимый для работы алгоритма котирования _trader.RegisterMarketDepth(_strategy.Security); _strategy.Start(); Start.Content = LocalizedStrings.Str242; } else { _trader.UnRegisterMarketDepth(_strategy.Security); _strategy.Stop(); Start.Content = LocalizedStrings.Str2421; } }
private void SetSource(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { List<RefPair<DateTimeOffset, IDictionary<IChartElement, object>>> values = null; lock (_syncRoot) { _indicators[element] = indicator; var isNew = !_elementsBySeries.ContainsKey(candleSeries); if (!isNew && CanProcess) { values = ProcessHistoryCandles(element, candleSeries); } else if (isNew) SubscribeSeries(candleSeries); var lastDate = values == null || values.IsEmpty() ? DateTimeOffset.MinValue : values.Last().First; _elementsInfo.SafeAdd(element, e => RefTuple.Create(lastDate, candleSeries)); _elementsBySeries.SafeAdd(candleSeries).Add(element); } if (values != null && values.Count > 0) new ChartDrawCommand(values).Process(this); }
private void Download_OnClick(object sender, RoutedEventArgs e) { var year = SelectedYear; var from = From.Value ?? year.Days.First(); var to = (To.Value ?? year.Days.Last()).EndOfDay(); var trader = SelectedTrader; var security = SelectedSecurity; var tf = SelectedTimeFrame; var series = new CandleSeries(typeof(TimeFrameCandle), security, tf); BusyIndicator.BusyContent = "Подготовка данных..."; BusyIndicator.IsBusy = true; Dictionary <DateTimeOffset, Tuple <MyTrade[], MyTrade> > trades = null; var worker = new BackgroundWorker { WorkerReportsProgress = true }; worker.DoWork += (o, ea) => { var candleStorage = _dataRegistry.GetCandleStorage(series, format: StorageFormats.Csv); _candles = candleStorage.Load(from, to); var candlesDatesCache = _candlesDates.SafeAdd(Tuple.Create(security, tf), k => new DatesCache(Path.Combine(((LocalMarketDataDrive)candleStorage.Drive.Drive).GetSecurityPath(security.ToSecurityId()), "{0}min_date.bin".Put((int)tf.TotalMinutes)))); var minCandleDate = candlesDatesCache.MinValue; var maxCandleDate = candlesDatesCache.MaxValue; if (from < minCandleDate || to > maxCandleDate) { var finamFrom = from; var finamTo = to; if (maxCandleDate != default(DateTime) && finamFrom >= minCandleDate && finamFrom <= maxCandleDate) { finamFrom = maxCandleDate + TimeSpan.FromDays(1); } if (minCandleDate != default(DateTime) && finamTo >= minCandleDate && finamTo <= maxCandleDate) { finamTo = minCandleDate - TimeSpan.FromDays(1); } if (finamTo > finamFrom) { worker.ReportProgress(1); var newCandles = (tf.Ticks == 1 ? finamFrom.Range(finamTo, TimeSpan.FromDays(1)).SelectMany(day => _finamHistorySource.GetTrades(security, day, day)).ToEx().ToCandles <TimeFrameCandle>(tf) : _finamHistorySource.GetCandles(security, tf, finamFrom, finamTo) ).ToArray(); candleStorage.Save(newCandles); foreach (var date in newCandles.Select(c => c.OpenTime.Date).Distinct()) { candlesDatesCache.Add(date); } candlesDatesCache.Save(); _candles = _candles.Concat(newCandles); } } var traderDrive = new LocalMarketDataDrive(trader); var traderStorage = _traderStorages.SafeAdd(trader, key => new StorageRegistry { DefaultDrive = traderDrive }); var olStorage = traderStorage.GetOrderLogStorage(security, format: StorageFormats.Csv); var tradeDatesCache = _tradesDates.SafeAdd(trader, k => new DatesCache(Path.Combine(traderDrive.Path, "dates.bin"))); trades = from .Range(to, TimeSpan.FromDays(1)) .Intersect(year.Days) .SelectMany(date => { if (olStorage.Dates.Contains(date)) { return(olStorage.Load(date)); } if (tradeDatesCache.Contains(date)) { return(Enumerable.Empty <OrderLogItem>()); } worker.ReportProgress(2, date); var loadedTrades = year.GetTrades(_securityStorage, trader, date); var secTrades = Enumerable.Empty <OrderLogItem>(); foreach (var group in loadedTrades.GroupBy(t => t.Order.Security)) { var sec = group.Key; traderStorage .GetOrderLogStorage(sec, format: StorageFormats.Csv) .Save(group.OrderBy(i => i.Order.Time)); if (group.Key == security) { secTrades = group; } } tradeDatesCache.Add(date); tradeDatesCache.Save(); return(secTrades); }) .GroupBy(ol => { var time = ol.Order.Time; var period = security.Board.WorkingTime.GetPeriod(time.DateTime); if (period != null && period.Times.Length > 0) { var last = period.Times.Last().Max; if (time.TimeOfDay >= last) { time = time.AddTicks(-1); } } return(time.Truncate(tf)); }) .ToDictionary(g => g.Key, g => { var candleTrades = g .Select(order => new MyTrade { Order = order.Order, Trade = order.Trade }) .ToArray(); if (candleTrades.Length > 0) { var order = candleTrades[0].Order; var volume = candleTrades.Sum(t1 => t1.Trade.Volume * (t1.Order.Direction == Sides.Buy ? 1 : -1)); if (volume == 0) { return(Tuple.Create(candleTrades, (MyTrade)null)); } var side = volume > 0 ? Sides.Buy : Sides.Sell; volume = volume.Abs(); var availableVolume = volume; var avgPrice = 0m; foreach (var trade in candleTrades.Where(t1 => t1.Order.Direction == side)) { var tradeVol = trade.Trade.Volume.Min(availableVolume); avgPrice += trade.Trade.Price * tradeVol; availableVolume -= tradeVol; if (availableVolume <= 0) { break; } } avgPrice = avgPrice / volume; return(Tuple.Create(candleTrades, new MyTrade { Order = new Order { Security = order.Security, Direction = side, Time = g.Key, Portfolio = order.Portfolio, Price = avgPrice, Volume = volume, }, Trade = new Trade { Security = order.Security, Time = g.Key, Volume = volume, Price = avgPrice } })); } return(null); }); }; worker.ProgressChanged += (o, ea) => { switch (ea.ProgressPercentage) { case 1: BusyIndicator.BusyContent = "Скачивание свечей..."; break; default: BusyIndicator.BusyContent = "Скачивание сделок за {0:yyyy-MM-dd}...".Put(ea.UserState); break; } }; worker.RunWorkerCompleted += (o, ea) => { BusyIndicator.IsBusy = false; if (ea.Error == null) { Chart.ClearAreas(); _statisticManager.Reset(); var area = new ChartArea(); area.YAxises.Add(new ChartAxis { Id = "equity", AutoRange = true, AxisType = ChartAxisType.Numeric, AxisAlignment = ChartAxisAlignment.Left, }); Chart.AddArea(area); var candlesElem = new ChartCandleElement { ShowAxisMarker = false }; Chart.AddElement(area, candlesElem, series); var tradesElem = new ChartTradeElement { BuyStrokeColor = Colors.Black, SellStrokeColor = Colors.Black, FullTitle = "trades", }; Chart.AddElement(area, tradesElem); var equityElem = new ChartIndicatorElement { YAxisId = "equity", FullTitle = "equity", IndicatorPainter = new PnlPainter() }; var equityInd = new SimpleMovingAverage { Length = 1 }; Chart.AddElement(area, equityElem); var positionArea = new ChartArea { Height = 200 }; Chart.AddArea(positionArea); var positionElem = new ChartIndicatorElement { FullTitle = "position" }; var positionInd = new SimpleMovingAverage { Length = 1 }; Chart.AddElement(positionArea, positionElem); Chart.IsAutoRange = true; var pnlQueue = new PnLQueue(security.ToSecurityId()); //var level1Info = new Level1ChangeMessage //{ // SecurityId = pnlQueue.SecurityId, //} //.TryAdd(Level1Fields.PriceStep, security.PriceStep) //.TryAdd(Level1Fields.StepPrice, security.StepPrice); //pnlQueue.ProcessLevel1(level1Info); var pos = 0m; var chartValues = _candles .Select(c => { c.State = CandleStates.Finished; pnlQueue.ProcessLevel1(new Level1ChangeMessage { SecurityId = security.ToSecurityId(), }.TryAdd(Level1Fields.LastTradePrice, c.ClosePrice)); var values = new Dictionary <IChartElement, object> { { candlesElem, c }, }; var candleTrade = trades.TryGetValue(c.OpenTime); if (candleTrade != null) { if (candleTrade.Item2 != null) { values.Add(tradesElem, candleTrade.Item2); } foreach (var myTrade in candleTrade.Item1) { pos += myTrade.Order.Direction == Sides.Buy ? myTrade.Trade.Volume : -myTrade.Trade.Volume; var pnl = pnlQueue.Process(myTrade.ToMessage()); _statisticManager.AddMyTrade(pnl); } _statisticManager.AddPosition(c.OpenTime, pos); _statisticManager.AddPnL(c.OpenTime, pnlQueue.RealizedPnL + pnlQueue.UnrealizedPnL); } values.Add(equityElem, equityInd.Process(pnlQueue.RealizedPnL + pnlQueue.UnrealizedPnL)); values.Add(positionElem, positionInd.Process(pos)); return(new RefPair <DateTimeOffset, IDictionary <IChartElement, object> > { First = c.OpenTime, Second = values }); }) .ToArray(); Chart.Draw(chartValues); Chart.IsAutoRange = false; } else { new MessageBoxBuilder() .Error() .Owner(this) .Text(ea.Error.ToString()) .Show(); } }; worker.RunWorkerAsync(); }
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; }
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 InitChart(EMAEventModelStrategy strategy) { _longMA = new ExponentialMovingAverage { Length = strategy.LongMA.Length}; _shortMA = new ExponentialMovingAverage { Length = strategy.ShortMA.Length }; _filterMA = new ExponentialMovingAverage { Length = strategy.FilterMA.Length }; _area.Elements.Clear(); _candlesElem = new ChartCandleElement() { DownBodyColor = Color.FromRgb(133, 133, 133), UpBodyColor = Color.FromRgb(255, 255, 255) }; _area.Elements.Add(_candlesElem); _longMaElem = new ChartIndicatorElement { Title = "LongMA", Indicator = _longMA, Color = Color.FromRgb(120, 199, 130) }; _area.Elements.Add(_longMaElem); _shortMaElem = new ChartIndicatorElement { Title = "ShortMA", Indicator = _shortMA, Color = Color.FromRgb(193, 53, 45) }; _area.Elements.Add(_shortMaElem); _filterMaElem = new ChartIndicatorElement { Title = "FilterMA", Indicator = _filterMA, Color = Color.FromRgb(0, 124, 207) }; _area.Elements.Add(_filterMaElem); _tradeElem = new ChartTradeElement() { BuyColor = Color.FromRgb(255, 0, 0), SellColor = Color.FromRgb(0, 0, 255), IsLegend = true }; _area.Elements.Add(_tradeElem); }