コード例 #1
0
        static void Main(string[] args)
        {
            Security sber = new Security {
                Id = "SBER@TQBR", Board = ExchangeBoard.Micex
            };
            Security gazp = new Security {
                Id = "GAZP@TQBS", Board = ExchangeBoard.Micex
            };
            Security gmkn = new Security {
                Id = "GMKN@TQBS", Board = ExchangeBoard.Micex
            };

            // создаем хранилище инструментов Финам
            // добавить инструменты можно через конструктор, так
            //var finamSecurityStorage = new FinamSecurityStorage(sber);
            // или так
            var finamSecurityStorage = new FinamSecurityStorage(new List <Security>()
            {
                sber, gmkn
            });

            // или при помощи метода Add
            finamSecurityStorage.Add(gazp);

            // Создаем экземпляр класса FinamHistorySource. Этот объект управляет получением данных с Финама.
            FinamHistorySource _finamHistorySource = new FinamHistorySource();

            // Создаем жранилище для нативных идентификаторов (родные идентификаторы инструментов Финама)
            var nativeIdStorage = new InMemoryNativeIdStorage();

            bool isCanceled = false;

            // Задаем папку, где будут сохранены запрошенные данные.. Если папку не задавать, то
            // на диске данные сохранены не будут
            _finamHistorySource.DumpFolder = "DataHist";

            // Выполняем обновление хранилища инструментов Финама
            // Перед добавлением каждого инструмента в хранилище вызывается функция (делегат) isCanceled, если функция возвращает false, то обновление
            // хранилища продолжается, если true, то прерывается.
            // При добавлении нового инструмента в хранилище вызывается функция (делегат) newSecurity. В нашем случае этот делегат имеет пустое тело (ничего не делает).
            _finamHistorySource.Refresh(finamSecurityStorage, nativeIdStorage, new Security(), s => {}, () => isCanceled);

            // Задаем таймфрем свечи
            var timeFrame = TimeSpan.FromMinutes(1);

            var now   = DateTime.Now;
            var end   = new DateTime(now.Year, now.Month, now.Day - 1, 0, 0, 0);
            var start = end.AddDays(-2);

            // Запрашиваем свечи с Финама
            var candles = _finamHistorySource.GetCandles(gazp, nativeIdStorage, timeFrame, start, end);

            // Запрашиваем тики
            var ticks = _finamHistorySource.GetTicks(gmkn, nativeIdStorage, start, end);

            Console.Read();
        }
コード例 #2
0
ファイル: MainWindow.xaml.cs プロジェクト: zli69/StockSharp
        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;
        }
コード例 #3
0
        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();
        }
コード例 #4
0
ファイル: FinamTask.cs プロジェクト: kknet/StockSharp
		protected override TimeSpan OnProcess()
		{
			var source = new FinamHistorySource();

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

			var allSecurity = this.GetAllSecurity();

			// если фильтр по инструментам выключен (выбран инструмент все инструменты)
			var selectedSecurities = (allSecurity != null ? this.ToHydraSecurities(_finamSecurityStorage.Securities) : Settings.Securities).ToArray();

			var hasNonFinam = selectedSecurities.Any(s => !IsFinam(s));

			if (selectedSecurities.IsEmpty() || hasNonFinam)
			{
				this.AddWarningLog(selectedSecurities.IsEmpty()
					? LocalizedStrings.Str2289
					: LocalizedStrings.Str2290.Put("Finam"));

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

				selectedSecurities = (allSecurity != null ? this.ToHydraSecurities(_finamSecurityStorage.Securities) : Settings.Securities)
					.Where(s =>
					{
						var retVal = IsFinam(s);

						if (!retVal)
							this.AddWarningLog(LocalizedStrings.Str2291Params, s.Security.Id, "Finam");

						return retVal;
					}).ToArray();
			}

			if (!CanProcess())
				return base.OnProcess();

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

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

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

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

				#region LoadTrades
				if ((allSecurity ?? security).MarketDataTypesSet.Contains(typeof(Trade)))
				{
					var storage = StorageRegistry.GetTradeStorage(security.Security, _settings.Drive, _settings.StorageFormat);
					var emptyDates = allDates.Except(storage.Dates).ToArray();

					if (emptyDates.IsEmpty())
					{
						this.AddInfoLog(LocalizedStrings.Str2293Params, security.Security.Id);
					}
					else
					{
						foreach (var emptyDate in emptyDates)
						{
							if (!CanProcess())
								break;

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

							try
							{
								this.AddInfoLog(LocalizedStrings.Str2294Params, emptyDate, security.Security.Id);
								var trades = source.GetTicks(security.Security, emptyDate, emptyDate);
								
								if (trades.Any())
									SaveTicks(security, trades);
								else
									this.AddDebugLog(LocalizedStrings.NoData);

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

				#endregion

				if (!CanProcess())
					break;

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

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

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

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

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

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

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

						try
						{
							var till = currDate.AddDays(_settings.CandleDayStep - 1);
							this.AddInfoLog(LocalizedStrings.Str2298Params, series.Arg, currDate, till, security.Security.Id);
							
							var candles = source.GetCandles(security.Security, (TimeSpan)series.Arg, currDate, till);
							
							if (candles.Any())
								SaveCandles(security, candles);
							else
								this.AddDebugLog(LocalizedStrings.NoData);

							if (_settings.UseTemporaryFiles == TempFiles.UseAndDelete)
								File.Delete(source.GetDumpFile(security.Security, currDate, till, typeof(TimeFrameCandleMessage), series.Arg));

							currDate = currDate.AddDays(_settings.CandleDayStep);
						}
						catch (Exception ex)
						{
							HandleError(new InvalidOperationException(LocalizedStrings.Str2299Params
								.Put(series.Arg, currDate, security.Security.Id), ex));
						}
					}
				}
				#endregion
			}

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

				_settings.StartFrom = endDate;
				SaveSettings();
			}

			return base.OnProcess();
		}
コード例 #5
0
        protected override TimeSpan OnProcess()
        {
            var source = new FinamHistorySource();

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

            var allSecurity = this.GetAllSecurity();

            // если фильтр по инструментам выключен (выбран инструмент все инструменты)
            var selectedSecurities = (allSecurity != null ? this.ToHydraSecurities(_finamSecurityStorage.Securities) : Settings.Securities).ToArray();

            var hasNonFinam = selectedSecurities.Any(s => !IsFinam(s));

            if (selectedSecurities.IsEmpty() || hasNonFinam)
            {
                this.AddWarningLog(selectedSecurities.IsEmpty()
                                        ? LocalizedStrings.Str2289
                                        : LocalizedStrings.Str2290.Put("Finam"));

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

                selectedSecurities = (allSecurity != null ? this.ToHydraSecurities(_finamSecurityStorage.Securities) : Settings.Securities)
                                     .Where(s =>
                {
                    var retVal = IsFinam(s);

                    if (!retVal)
                    {
                        this.AddWarningLog(LocalizedStrings.Str2291Params, s.Security.Id, "Finam");
                    }

                    return(retVal);
                }).ToArray();
            }

            if (!CanProcess())
            {
                return(base.OnProcess());
            }

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

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

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

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

                #region LoadTrades
                if ((allSecurity ?? security).MarketDataTypesSet.Contains(typeof(Trade)))
                {
                    var storage    = StorageRegistry.GetTradeStorage(security.Security, _settings.Drive, _settings.StorageFormat);
                    var emptyDates = allDates.Except(storage.Dates).ToArray();

                    if (emptyDates.IsEmpty())
                    {
                        this.AddInfoLog(LocalizedStrings.Str2293Params, security.Security.Id);
                    }
                    else
                    {
                        foreach (var emptyDate in emptyDates)
                        {
                            if (!CanProcess())
                            {
                                break;
                            }

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

                            try
                            {
                                this.AddInfoLog(LocalizedStrings.Str2294Params, emptyDate, security.Security.Id);
                                var trades = source.GetTrades(security.Security, emptyDate, emptyDate);

                                if (trades.Any())
                                {
                                    SaveTrades(security, trades);
                                }
                                else
                                {
                                    this.AddDebugLog(LocalizedStrings.NoData);
                                }

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

                #endregion

                if (!CanProcess())
                {
                    break;
                }

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

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

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

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

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

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

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

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

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

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

                _settings.StartFrom = endDate;
                SaveSettings();
            }

            return(base.OnProcess());
        }
コード例 #6
0
        private void Download_OnClick(object sender, RoutedEventArgs e)
        {
            var settings = new Settings
            {
                Year      = SelectedYear.Year,
                Trader    = Trader.Text,
                From      = From.Value,
                To        = To.Value,
                Security1 = Security1.Text,
                Security2 = Security2.Text,
                Security3 = Security3.Text,
                Security4 = Security4.Text,
                TimeFrame = SelectedTimeFrame,
                Apart     = Apart.IsChecked == true,
            };

            CultureInfo.InvariantCulture.DoInCulture(() => new XmlSerializer <SettingsStorage>().Serialize(settings.Save(), _settingsFile));

            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 apart  = Apart.IsChecked == true;

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

                    TimeFrameCandle[] newCandles;

                    if (tf.Ticks == 1)
                    {
                        newCandles = finamFrom.Range(finamTo, TimeSpan.FromDays(1)).SelectMany(day =>
                        {
                            worker.ReportProgress(1, Tuple.Create(security, day));

                            var candles = _finamHistorySource.GetTrades(security, day, day).ToEx().ToCandles <TimeFrameCandle>(tf).ToArray();
                            candleStorage.Save(candles);
                            candlesDatesCache.Add(day);
                            return(candles);
                        }).ToArray();
                    }
                    else
                    {
                        worker.ReportProgress(1, Tuple.Create(security, finamFrom, finamTo));
                        newCandles = _finamHistorySource.GetCandles(security, tf, finamFrom, finamTo).ToArray();

                        candleStorage.Save(newCandles);
                        candlesDatesCache.Add(newCandles.Select(c => c.OpenTime.Date).Distinct().ToArray());
                    }

                    // TODO
                    secCandles.AddRange(newCandles);
                }

                var traderDrive   = new LocalMarketDataDrive(Path.Combine(_settingsDir, 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.xml")));

                    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);

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

                        if (tf == TimeSpan.FromDays(1) && period != null && period.Times.Length > 0)
                        {
                            return(new DateTimeOffset(time.Date + period.Times[0].Min, time.Offset));
                        }

                        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:
                {
                    if (ea.UserState is Tuple <Security, DateTime> )
                    {
                        BusyIndicator.BusyContent = "Скачивание {Item1.Id} тиков за {Item2:yyyy-MM-dd}...".PutEx(ea.UserState);
                    }
                    else
                    {
                        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 equityInd = new SimpleMovingAverage {
                        Length = 1
                    };
                    ChartIndicatorElement equityElem;
                    var candlesAreas = new Dictionary <CandleSeries, ChartArea>();

                    if (apart)
                    {
                        foreach (var series in seriesSet)
                        {
                            var area = new ChartArea {
                                Title = series.Item1.Security.Id
                            };
                            Chart.AddArea(area);
                            area.YAxises.Clear();
                            candlesAreas.Add(series.Item1, area);
                        }

                        var equityArea = new ChartArea {
                            Title = LocalizedStrings.PnL
                        };
                        Chart.AddArea(equityArea);

                        equityElem = new ChartIndicatorElement
                        {
                            FullTitle        = LocalizedStrings.PnL,
                            IndicatorPainter = new PnlPainter()
                        };
                        Chart.AddElement(equityArea, equityElem);
                    }
                    else
                    {
                        var candlesArea = new ChartArea();
                        Chart.AddArea(candlesArea);

                        foreach (var tuple in seriesSet)
                        {
                            candlesAreas.Add(tuple.Item1, candlesArea);
                        }

                        const string equityYAxis = "Equity";

                        candlesArea.YAxises.Clear();
                        candlesArea.YAxises.Add(new ChartAxis
                        {
                            Id            = equityYAxis,
                            AutoRange     = true,
                            AxisType      = ChartAxisType.Numeric,
                            AxisAlignment = ChartAxisAlignment.Left,
                        });
                        equityElem = new ChartIndicatorElement
                        {
                            YAxisId          = equityYAxis,
                            FullTitle        = LocalizedStrings.PnL,
                            IndicatorPainter = new PnlPainter()
                        };
                        Chart.AddElement(candlesArea, equityElem);
                    }

                    var positionArea = new ChartArea {
                        Height = 100
                    };
                    Chart.AddArea(positionArea);
                    positionArea.YAxises.Clear();

                    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;

                        var candlesArea = candlesAreas[series.Item1];

                        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();
        }