﻿<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type='text/css' href='https://stocksharp.com/css/style.css'?>
<?xml-stylesheet type='text/css' href='https://stocksharp.com/css/bbeditor.css'?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="html">Проба пера: SampleSpreadHistoryTesting</title>
  <id>~/topic/2341/proba-pera-samplespreadhistorytesting/</id>
  <rights type="text">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  <updated>2026-04-22T08:53:16Z</updated>
  <logo>https://stocksharp.com/images/logo.png</logo>
  <link href="https://stocksharp.com/handlers/atom.ashx?category=topic&amp;id=2341" rel="self" type="application/rss+xml" />
  <entry>
    <id>https://stocksharp.com/posts/m/15920/</id>
    <title type="text">Предлагаю создать пример для тестирования стратегий на исторических данных по стаканам. MainWindow.x...</title>
    <published>2012-01-25T08:20:08Z</published>
    <updated>2012-02-01T19:18:00Z</updated>
    <author>
      <name>ingeniero</name>
      <uri>https://stocksharp.com/users/28032/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">Предлагаю создать пример для тестирования стратегий на исторических данных по стаканам.&lt;br /&gt;&lt;br /&gt;MainWindow.xaml.cs&lt;br /&gt;&lt;div class='spoilertitle'&gt;&lt;input type='button' value='Show spoiler' class='btn btn-primary' onclick="toggleSpoiler(this, 'spolier_0c9ea3681c8e4bba8dcabfb9673af653');" title='Show spoiler' /&gt;&lt;/div&gt;&lt;div class='spoilerbox' id='spolier_0c9ea3681c8e4bba8dcabfb9673af653' style='display:none'&gt;&lt;div class="code"&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;
namespace SampleSpreadHistoryTesting
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Windows;
    using System.Windows.Forms;
    using System.Windows.Media;
    using MessageBox = System.Windows.MessageBox;
    using StockSharp.Algo.Equity;
    using StockSharp.Algo.Logging;
    using StockSharp.Algo.Reporting;
    using StockSharp.Algo.Storages;
    using StockSharp.Algo.Strategies;
    using StockSharp.Algo.Testing;
    using StockSharp.BusinessEntities;
    using Ecng.Collections;
    using Ecng.Common;
    using Ecng.Serialization;
    using Ecng.Xaml;

    public partial class MainWindow
    {
        private ICollection&amp;lt;EquityData&amp;gt; _curveItems;
        private readonly LogManager _logManager = new LogManager();
        private DateTime _lastUpdateDate;
        private DateTime _startEmulationTime;

        public void LogManager()
        {
            InitializeComponent();
            _logManager.Listeners.Add(new FileLogListener(&amp;quot;log.txt&amp;quot;));
        }

        private void FindPathClick(object sender, RoutedEventArgs e)
        {
            var dlg = new FolderBrowserDialog();

            if (!HistoryPath.Text.IsEmpty())
                dlg.SelectedPath = HistoryPath.Text;

            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                HistoryPath.Text = dlg.SelectedPath;
            }
        }

        public void StartBtnClick(object sender, RoutedEventArgs e)
        {
            // создаем хранилище для работы с базой данных котировок
            var storage =
                new TradingStorage(new InMemoryStorage())
                    {
                        BasePath = HistoryPath.Text
                    };

            if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text))
            {
                MessageBox.Show(this, &amp;quot;Неправильный путь&amp;quot;);
                return;
            }

            // выбираем интервал времени для тестирования (таймфрейм)
            var timeFrame = TimeSpan.FromTicks(1);

            // устанавливаем период тестирования (зависит от объема данных, хранящихся по пути HistoryPath) 
            var startTime = new DateTime(2012, 1, 1);
            var stopTime = new DateTime(2012, 2, 1);

            // создаем тестовый портфель
            var portfolio =
                new Portfolio
                    {
                        BeginAmount = 1000000m,
                        Name = &amp;quot;Test account&amp;quot;
                    };

            // создаем первый инструмент спреда
            var security1 =
                new Security
                    {
                        Code = &amp;quot;SBER&amp;quot;,
                        Exchange = Exchange.Test,
                        // идентификатор инструмента, по которому будет осуществлен поиск папки с историей стаканов
                        Id = &amp;quot;SBER@EQBR&amp;quot;,
                        MinStepPrice = 0.01m,
                        MinStepSize = 0.01m,
                        Name = &amp;quot;Сбербанк России ОАО ао&amp;quot;
                    };

            // создаем второй инструмент спреда
            var security2 =
                new Security
                    {
                        Code = &amp;quot;SRH2&amp;quot;,
                        Exchange = Exchange.Test,
                        // идентификатор инструмента, по которому будет осуществлен поиск папки с историей стаканов
                        Id = &amp;quot;SRH2@RTS&amp;quot;,
                        MinStepPrice = 1,
                        MinStepSize = 1,
                        Name = &amp;quot;SBRF-3.12&amp;quot;
                    };

            // создаем стратегию для торговли спредом
            var spreadStrategy =
                new SpreadStrategy(security1, security2)
                    {
                        Security1 = security1,
                        Security2 = security2
                    };
            
            // создаем шлюз для торговли
            var trader =
                new EmulationTrader(new[] {security1, security2}, new[] {portfolio})
                    {
                        // параметр влияет на занимаемую память (в случае достаточного объема памяти лучше увеличить)
                        DaysInMemory = 2,
                        MarketTimeChangedInterval = timeFrame,
                        Storage = storage,
                        WorkingTime = Exchange.Micex.WorkingTime
                    };

            // если процесс был запущен, останавливаем его
            if (trader.State != EmulationStates.Stopped)
            {
                StartBtn.IsEnabled = false;
                spreadStrategy.Stop();
                trader.Stop();
                _logManager.Sources.Clear();
                return;
            }

            trader.DepthGenerators[security1] =
                new TrendMarketDepthGenerator(security1)
                    {
                        // время обновления стакана в базе данных для первого инструмента
                        Interval = TimeSpan.FromTicks(1)
                    };

            trader.DepthGenerators[security2] =
                new TrendMarketDepthGenerator(security2)
                    {
                        // время обновления стакана в базе данных для второго инструмента
                        Interval = TimeSpan.FromTicks(1)
                    };

            // копируем параметры на визуальную панель
            ParametersPanel.Parameters.Clear();
            ParametersPanel.Parameters.AddRange(spreadStrategy.EquityManager.Parameters);

            if (_curveItems == null)
                _curveItems = Curve.CreateCurve(spreadStrategy.Name, Colors.DarkGreen);
            else
            _curveItems.Clear();

            spreadStrategy.EquityManager.NewEquityData += data =&amp;gt; this.GuiAsync(() =&amp;gt; _curveItems.Add(data));
            _logManager.Sources.Add(spreadStrategy);

            // подписываемся на событие изменения времени, чтобы обновить ProgressBar
            trader.MarketTimeChanged +=
                () =&amp;gt;
                    {
                        // для оптимизации обновляем ProgressBar только при начале нового дня
                        if (trader.MarketTime.Date == _lastUpdateDate &amp;amp;&amp;amp; trader.MarketTime &amp;lt; stopTime) return;
                        _lastUpdateDate = trader.MarketTime.Date;
                        this.GuiAsync(() =&amp;gt; TestingProcess.Value = (trader.MarketTime - startTime).Ticks);
                    };

            trader.StateChanged +=
                () =&amp;gt;
                    {
                        switch (trader.State)
                        {
                            case EmulationStates.Stopped:
                                this.GuiAsync(
                                    () =&amp;gt;
                                        {
                                            StartBtn.IsEnabled = true;
                                            if (Convert.ToDecimal(TestingProcess.Value) ==
                                                Convert.ToDecimal(TestingProcess.Maximum))
                                                MessageBox.Show(&amp;quot;Закончено за &amp;quot; + (DateTime.Now - _startEmulationTime));
                                            else
                                            MessageBox.Show(&amp;quot;Отменено&amp;quot;);
                                        });
                                break;
                            case EmulationStates.Started:
                                // запускаем стратегию, когда эмулятор запустился
                                spreadStrategy.Start();
                                break;
                        }
                    };

            // устанавливаем в визуальный элемент ProgressBar максимальное количество итераций
            TestingProcess.Maximum = (stopTime - startTime).Ticks;
            TestingProcess.Value = 0;
            Report.IsEnabled = true;

            _startEmulationTime = DateTime.Now;

            // устанавливаем соединение и запускаем экспорт
            trader.Connect();
            trader.StartExport();

            // задаем период тестирования (startTime, stopTime) и запускаем эмуляцию
            trader.Start(startTime, stopTime);
        }

        private void ReportClick(object sender, RoutedEventArgs e)
        {
            // генерируем отчет по прошедшему тестированию (Excel может тормозить из-за большого количества данных)
            new ExcelStrategyReport(ExcelStrategy, &amp;quot;sma.xls&amp;quot;).Generate();

            // открываем отчет
            Process.Start(&amp;quot;sma.xls&amp;quot;);
        }

        public Strategy ExcelStrategy { get; set; }
    }
}&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;SpreadStrategy.cs&lt;br /&gt;&lt;div class='spoilertitle'&gt;&lt;input type='button' value='Show spoiler' class='btn btn-primary' onclick="toggleSpoiler(this, 'spolier_7f74edb1a4e6463591953ec766327363');" title='Show spoiler' /&gt;&lt;/div&gt;&lt;div class='spoilerbox' id='spolier_7f74edb1a4e6463591953ec766327363' style='display:none'&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;
namespace SampleSpreadHistoryTesting
{
    using System;
    using StockSharp.Algo;
    using StockSharp.Algo.Strategies;
    using StockSharp.BusinessEntities;

    class SpreadStrategy : Strategy
    {
        public decimal SpreadSellDelta;
        public decimal SpreadBuyDelta;
        public Security Security1 = new Security();
        public Security Security2 = new Security();

        public SpreadStrategy(Security security1, Security security2)
        {
            Security1 = security1;
            Security2 = security2;
        }

        protected override void  OnStarting()
        {
            decimal priceRatio;

            if (Security2.MinStepPrice &amp;gt; Security1.MinStepPrice)
                // вычисляем соотношение цен инструментов
                priceRatio = Security2.MinStepPrice/Security1.MinStepPrice;
            else
            priceRatio = Security1.MinStepPrice/Security2.MinStepPrice;

            // для продажи спреда вычисляем разность между ценой покупки второго актива и ценой продажи первого
            SpreadSellDelta = Convert.ToDecimal(Security2.BestAsk) - Convert.ToDecimal(Security1.BestBid)*priceRatio;
            
            // для покупки спреда вычисляем разность между ценой продажи второго актива и ценой покупки первого
            SpreadBuyDelta = Convert.ToDecimal(Security2.BestBid) - Convert.ToDecimal(Security1.BestAsk)*priceRatio;

            base.OnStarting();
        }

        protected ProcessResults OnProcess()
        {
            // если наша стратегия в процессе остановки
			if (ProcessState == ProcessStates.Stopping)
			{
				// отменяем активные заявки
				CancelActiveOrders();

				// так как все активные заявки гарантированно были отменены, то возвращаем ProcessResults.Stop
				return ProcessResults.Stop;
			}

            // задаем интервал для торговли спредом
            const decimal spreadSellPrice = 100m;
            const decimal spreadBuyPrice = -100m;

            // проверяем сигнал на продажу спреда
            if (SpreadSellDelta &amp;lt; spreadSellPrice) return ProcessResults.Continue;
            {
                // продажа спреда
                const OrderDirections direction1 = OrderDirections.Buy;
                const OrderDirections direction2 = OrderDirections.Sell;

                // регистрируем заявки
                var orderSecurity1 = this.CreateOrder(direction1, Security1.GetMarketPrice(direction1), 100m);
                RegisterOrder(orderSecurity1);
                var orderSecurity2 = this.CreateOrder(direction2, Security2.GetMarketPrice(direction2), 1m);
                RegisterOrder(orderSecurity2);
            }

            // проверяем сигнал на покупку спреда
            if (SpreadBuyDelta &amp;gt; spreadBuyPrice) return ProcessResults.Continue;
            {
                // покупка спреда
                const OrderDirections direction1 = OrderDirections.Sell;
                const OrderDirections direction2 = OrderDirections.Buy;

                // регистрируем заявки
                var orderSecurity1 = this.CreateOrder(direction1, Security1.GetMarketPrice(direction1), 100m);
                RegisterOrder(orderSecurity1);
                var orderSecurity2 = this.CreateOrder(direction2, Security2.GetMarketPrice(direction2), 1m);
                RegisterOrder(orderSecurity2);
            }

            return ProcessResults.Continue;
        }
    }
}&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;MainWindow.xaml&lt;br /&gt;&lt;div class='spoilertitle'&gt;&lt;input type='button' value='Show spoiler' class='btn btn-primary' onclick="toggleSpoiler(this, 'spolier_9d775590b4bd4cdd991fdd7e21d46029');" title='Show spoiler' /&gt;&lt;/div&gt;&lt;div class='spoilerbox' id='spolier_9d775590b4bd4cdd991fdd7e21d46029' style='display:none'&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:xml"&gt;

&amp;lt;Window x:Class=&amp;quot;SampleSpreadHistoryTesting.MainWindow&amp;quot;
        xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
        xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
        xmlns:my=&amp;quot;clr-namespace:StockSharp.Xaml;assembly=StockSharp.Xaml&amp;quot; Title=&amp;quot;Тестирование по стаканам&amp;quot; Height=&amp;quot;300&amp;quot; Width=&amp;quot;525&amp;quot;&amp;gt;
    
    &amp;lt;Grid&amp;gt;
        &amp;lt;Grid.ColumnDefinitions&amp;gt;
            &amp;lt;ColumnDefinition Width=&amp;quot;15*&amp;quot; /&amp;gt;
            &amp;lt;ColumnDefinition Width=&amp;quot;85*&amp;quot; /&amp;gt;
        &amp;lt;/Grid.ColumnDefinitions&amp;gt;
        &amp;lt;Grid.RowDefinitions&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;Auto&amp;quot;/&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;*&amp;quot;/&amp;gt;
        &amp;lt;/Grid.RowDefinitions&amp;gt;
        &amp;lt;Grid Grid.ColumnSpan=&amp;quot;2&amp;quot;&amp;gt;
            &amp;lt;Grid.ColumnDefinitions&amp;gt;
                &amp;lt;ColumnDefinition Width=&amp;quot;100&amp;quot; /&amp;gt;
                &amp;lt;ColumnDefinition Width=&amp;quot;*&amp;quot; /&amp;gt;
                &amp;lt;ColumnDefinition Width=&amp;quot;Auto&amp;quot; /&amp;gt;
            &amp;lt;/Grid.ColumnDefinitions&amp;gt;
            &amp;lt;Grid.RowDefinitions&amp;gt;
                &amp;lt;RowDefinition Height=&amp;quot;Auto&amp;quot; /&amp;gt;
                &amp;lt;RowDefinition Height=&amp;quot;10&amp;quot; /&amp;gt;
                &amp;lt;RowDefinition Height=&amp;quot;Auto&amp;quot; /&amp;gt;
                &amp;lt;RowDefinition Height=&amp;quot;10&amp;quot; /&amp;gt;
            &amp;lt;/Grid.RowDefinitions&amp;gt;

            &amp;lt;Label Grid.Column=&amp;quot;0&amp;quot; Grid.Row=&amp;quot;0&amp;quot; Content=&amp;quot;Путь к истории:&amp;quot; /&amp;gt;
            &amp;lt;TextBox x:Name=&amp;quot;HistoryPath&amp;quot; Text=&amp;quot;&amp;quot; Grid.Column=&amp;quot;1&amp;quot; Grid.Row=&amp;quot;0&amp;quot; /&amp;gt;
            &amp;lt;Button x:Name=&amp;quot;FindPath&amp;quot; Grid.Column=&amp;quot;2&amp;quot; Grid.Row=&amp;quot;0&amp;quot; Content=&amp;quot;...&amp;quot; Width=&amp;quot;25&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; Click=&amp;quot;FindPathClick&amp;quot; /&amp;gt;

            &amp;lt;Button x:Name=&amp;quot;StartBtn&amp;quot; Content=&amp;quot;Старт&amp;quot; Grid.Row=&amp;quot;2&amp;quot; Click=&amp;quot;StartBtnClick&amp;quot; /&amp;gt;
            &amp;lt;ProgressBar x:Name=&amp;quot;TestingProcess&amp;quot; Grid.Column=&amp;quot;1&amp;quot; Grid.Row=&amp;quot;2&amp;quot; /&amp;gt;

            &amp;lt;Button x:Name=&amp;quot;Report&amp;quot; Content=&amp;quot;Отчет&amp;quot; Grid.Row=&amp;quot;2&amp;quot; Width=&amp;quot;75&amp;quot; IsEnabled=&amp;quot;False&amp;quot; Click=&amp;quot;ReportClick&amp;quot; Grid.Column=&amp;quot;2&amp;quot; Margin=&amp;quot;0,0,0,-1&amp;quot; /&amp;gt;
        &amp;lt;/Grid&amp;gt;
        &amp;lt;Grid Grid.Row=&amp;quot;2&amp;quot; Grid.ColumnSpan=&amp;quot;2&amp;quot;&amp;gt;
            &amp;lt;Grid&amp;gt;
                &amp;lt;Grid.ColumnDefinitions&amp;gt;
                    &amp;lt;ColumnDefinition Width=&amp;quot;180&amp;quot;/&amp;gt;
                    &amp;lt;ColumnDefinition Width=&amp;quot;*&amp;quot;/&amp;gt;
                &amp;lt;/Grid.ColumnDefinitions&amp;gt;

                &amp;lt;my:EquityParameterPanel Grid.Column=&amp;quot;0&amp;quot; x:Name=&amp;quot;ParametersPanel&amp;quot; /&amp;gt;
                &amp;lt;my:EquityCurveChart Grid.Column=&amp;quot;1&amp;quot; x:Name=&amp;quot;Curve&amp;quot; /&amp;gt;
            &amp;lt;/Grid&amp;gt;
        &amp;lt;/Grid&amp;gt;
        
    &amp;lt;/Grid&amp;gt;
&amp;lt;/Window&amp;gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Прошу форумчан высказывать свои пожелания относительно стратегии и помочь в решении существующих проблем.&lt;br /&gt;При внесении изменений верхний пост будет редактироваться.&lt;br /&gt;&lt;br /&gt;Список нерешенных проблем:&lt;br /&gt;1) При запуске приложения не создается лог-файл&lt;br /&gt;2) Не производится тестирование&lt;br /&gt;3) Не генерируется отчет по тестированию&lt;br /&gt;4) Нет возможности построить график спреда для дальнейшего анализа&lt;br /&gt;5) Необходимо подробное условие для входа и выхода из позиции (на основании графика спреда)&lt;br /&gt;6) Проверка текущего лимита средств, исполненных заявок (расчет суммарной дельты портфеля)&lt;br /&gt;7) Переменные для указания количества ценных бумаг в заявке</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/16077/</id>
    <title type="text">freelancer, JackSparrow, спасибо. Убрал ChildStrategies, вынес стратегию в отдельный класс. К сожале...</title>
    <published>2012-02-01T14:48:28Z</published>
    <updated>2012-02-01T14:48:28Z</updated>
    <author>
      <name>ingeniero</name>
      <uri>https://stocksharp.com/users/28032/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">freelancer, JackSparrow, спасибо.&lt;br /&gt;Убрал ChildStrategies, вынес стратегию в отдельный класс.&lt;br /&gt;К сожалению, на работоспособность приложения это не повлияло:)</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/15928/</id>
    <title type="text">Да.Оболочка + Стратегии</title>
    <published>2012-01-25T10:58:11Z</published>
    <updated>2012-01-25T10:58:11Z</updated>
    <author>
      <name>freelancer</name>
      <uri>https://stocksharp.com/users/28572/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">Да.Оболочка + Стратегии</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/15926/</id>
    <title type="text">Вроде как бизнес логику надо прописать в классе создавнной стратегии а не в методе обработчика клика...</title>
    <published>2012-01-25T09:44:12Z</published>
    <updated>2012-01-25T09:44:12Z</updated>
    <author>
      <name>JackSparrow</name>
      <uri>https://stocksharp.com/users/27783/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">Вроде как бизнес логику надо прописать в классе создавнной стратегии а не в методе обработчика клика  ( MainWindow.StartBtnClik ).&lt;br /&gt;По клику создаем и запускаем а потом уже трейдер сам со стратегией общается.&lt;br /&gt;&lt;br /&gt;Это первое что увидел.</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/15922/</id>
    <title type="text">Что за рекурсия spreadStrategy.ChildStrategies.Add(spreadStrategy) ?</title>
    <published>2012-01-25T08:49:10Z</published>
    <updated>2012-01-25T08:49:10Z</updated>
    <author>
      <name>freelancer</name>
      <uri>https://stocksharp.com/users/28572/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">Что за рекурсия spreadStrategy.ChildStrategies.Add(spreadStrategy) ?</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
</feed>