﻿<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type='text/css' href='https://stocksharp.ru/css/style.css'?>
<?xml-stylesheet type='text/css' href='https://stocksharp.ru/css/bbeditor.css'?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="html">S#.Shell. Manual</title>
  <id>~/topic/4045/s_shell_-manual/</id>
  <rights type="text">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  <updated>2026-04-26T03:12:53Z</updated>
  <logo>https://stocksharp.ru/images/logo.png</logo>
  <link href="https://stocksharp.ru/handlers/atom.ashx?category=topic&amp;id=4045" rel="self" type="application/rss+xml" />
  <entry>
    <id>https://stocksharp.ru/posts/m/29961/</id>
    <title type="text">methyst, тут такие правила что по окончанию срока обучения (1,5 или 3 мес ) пользователей отключают ...</title>
    <published>2014-03-11T16:09:32Z</published>
    <updated>2016-08-16T00:17:08Z</updated>
    <author>
      <name>Mikhail Sukhov</name>
      <uri>https://stocksharp.ru/users/201/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">&lt;div class="quote"&gt;&lt;span class="quotetitle"&gt;lebedevsrg &lt;a href="https://stocksharp.ru/posts/m/29945/" class="quote_nav"&gt;&lt;/a&gt;&lt;/span&gt;&lt;div class="innerquote"&gt;methyst, тут такие правила что по окончанию срока обучения (1,5 или 3 мес ) пользователей отключают от TFS.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Таких правил нет. &lt;a href="http://stocksharp.com/posts/m/29944/" title="http://stocksharp.com/posts/m/29944/"&gt;http://stocksharp.com/posts/m/29944/&lt;/a&gt;</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/31815/</id>
    <title type="text">Часть 10 - Обеспечение стабильной работы робота Итак после всех мероприятий робот работает стабильно...</title>
    <published>2014-10-05T06:34:08Z</published>
    <updated>2014-10-05T07:20:26Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">&lt;b&gt;Часть 10 - Обеспечение стабильной работы робота&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Итак после всех мероприятий робот работает стабильно, торгует и восстанавливает при сбоях позиции - и самое главное -  зарабатывает деньги.&lt;br /&gt;Но только КОГДА работает!&lt;br /&gt;&lt;br /&gt;И тут возникают две дополнительные проблемы с обеспечением стабильности работы.&lt;br /&gt;&lt;br /&gt;1. Автоматический запуск и начало работы&lt;br /&gt;Торги на ММВБ начинаются в 10 и завершаются в 23:45, соответственно ставим задачу на автозапуск ПК в 09:55 и погружаем ПК на ночь в соню.&lt;br /&gt;И тут утром обнаруживается, что по истечении 5 минут работы система автоматически переходит в режим сна!&lt;br /&gt;При этом настройки питания - &amp;quot;высокая производительность&amp;quot;, т.е. никаких отключений по времени.&lt;br /&gt;Начинаем разбираться и выясняем, что при использовании SSD-накопителей &amp;quot;умные&amp;quot; драйверы Windows8 мониторят действия пользователя (мыши, клавиатуры) и при их отсутствии все равно усыпляют ПК. Отключить это невозможно.&lt;br /&gt;Итак - лечим это через С#.&lt;br /&gt;&lt;br /&gt;1) Создаем класс MouseOperations, в который выносим основные функции эмуляции управления мышью:&lt;br /&gt;- SetCursorPosition,&lt;br /&gt;- GetCursorPosition,&lt;br /&gt;- MouseEvent.&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

class MouseOperations
    {
        [Flags]
        public enum MouseEventFlags
        {
            LeftDown = 0x00000002,
            LeftUp = 0x00000004,
            MiddleDown = 0x00000020,
            MiddleUp = 0x00000040,
            Move = 0x00000001,
            Absolute = 0x00008000,
            RightDown = 0x00000008,
            RightUp = 0x00000010
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MousePoint
        {
            public int X;
            public int Y;

            public MousePoint(int x, int y)
            {
                X = x;
                Y = y;
            }
        }


        [DllImport(&amp;quot;user32.dll&amp;quot;, EntryPoint = &amp;quot;SetCursorPos&amp;quot;)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetCursorPos(int X, int Y);

        [DllImport(&amp;quot;user32.dll&amp;quot;)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetCursorPos(out MousePoint lpMousePoint);

        [DllImport(&amp;quot;user32.dll&amp;quot;)]
        private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);

        public static void SetCursorPosition(int X, int Y)
        {
            SetCursorPos(X, Y);
        }

        public static void SetCursorPosition(MousePoint point)
        {
            SetCursorPos(point.X, point.Y);
        }

        public static MousePoint GetCursorPosition()
        {
            MousePoint currentMousePoint;
            var gotPoint = GetCursorPos(out currentMousePoint);
            if (!gotPoint) { currentMousePoint = new MousePoint(0, 0); }
            return currentMousePoint;
        }

        public static void MouseEvent(MouseEventFlags value)
        {
            MousePoint position = GetCursorPosition();

            mouse_event
                ((int)value,
                 position.X,
                 position.Y,
                 0,
                 0);
        }
    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;При этом данные функции нужно делать именно производными от системной библиотеки user32.dll, т.к. &lt;br /&gt;использование System.Windows.Forms.Cursor и System.Windows.Input.Cursor не дет нужного эффекта - это все го лишь функции отрисовки изображения курсора, а нам нужны функции эмуляции работы мыши.&lt;br /&gt;&lt;br /&gt;2) в этом же классе создаем функцию отрисовки движения мыши по экрану:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

public static void BresenhamCircle(int x0, int y0, int radius)
        {
            int x = radius;
            int y = 0;
            int radiusError = 1 - x;
            while (x &amp;gt;= y)
            {
                
                SetCursorPosition(x + x0, y + y0);
                SetCursorPosition(y + x0, x + y0);
                SetCursorPosition(-x + x0, y + y0);
                

                y++;
                if (radiusError &amp;lt; 0)
                {
                    radiusError += 2 * y + 1;
                }
                else
                {
                    x--;
                    radiusError += 2 * (y - x + 1);
                }
            }
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;3) вызываем функцию из какого-либо переодического события, например из функции OnTimeChanged(), по которой робот проверяет время работы стратегии &lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

var isContain = Helper.Contains(strategy.Params.Schedule, time);
if (isContain) MouseOperations.BresenhamCircle(200, 200, 200); 
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;И вот каждые 30сек мы получаем маленькое и практически незаметное для пользователя подергивание мышки, которое однако выполняет свою основную функцию - предотвращает погружение ПК в преждевременный сон.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. Женский пол.&lt;br /&gt;Это у меня оказалось второй проблемой, так как приходя домой раньше меня девушка каждый раз &amp;quot;нечаянно&amp;quot; выключала работа)) И хотя вечерняя сессия не такая бурная по событиям как дневная, но все я стал фиксить упущенные из-за этого прибыльные сделки.&lt;br /&gt;И тут мы открываем для себя мир ситемного треша, в смысле трея))&lt;br /&gt;&lt;br /&gt;1) устанавливаем NU-get пакет Hardcodet.NotifyIcon.Wpf, который обеспечивает работы с иконками в системной трее.&lt;br /&gt;&lt;br /&gt;2) создаем пользовательский словарь ресурсов SysTrayResources.xaml, в котором создаем  TaskbarIcon - объект иконки с системной трее, и его контекстное меню&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

&amp;lt;ResourceDictionary 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:tb=&amp;quot;http://www.hardcodet.net/taskbar&amp;quot;
                    xmlns:robot=&amp;quot;clr-namespace:Robot&amp;quot;&amp;gt;

    
  &amp;lt;ContextMenu x:Shared=&amp;quot;false&amp;quot; x:Key=&amp;quot;SysTrayMenu&amp;quot;&amp;gt;
        &amp;lt;MenuItem Header=&amp;quot;Show Window&amp;quot; Command=&amp;quot;{Binding ShowWindowCommand}&amp;quot; /&amp;gt;
        &amp;lt;MenuItem Header=&amp;quot;Hide Window&amp;quot; Command=&amp;quot;{Binding HideWindowCommand}&amp;quot; /&amp;gt;
        &amp;lt;Separator /&amp;gt;
        &amp;lt;MenuItem Header=&amp;quot;Exit&amp;quot; Command=&amp;quot;{Binding ExitApplicationCommand}&amp;quot; /&amp;gt;
    &amp;lt;/ContextMenu&amp;gt;


    &amp;lt;tb:TaskbarIcon x:Key=&amp;quot;SysTrayIcon&amp;quot;
                    IconSource=&amp;quot;/Service/stocksharp.ico&amp;quot;
                    ToolTipText=&amp;quot;&amp;quot;
                    DoubleClickCommand=&amp;quot;{Binding ShowWindowCommand}&amp;quot;
                    ContextMenu=&amp;quot;{StaticResource SysTrayMenu}&amp;quot;&amp;gt;

        &amp;lt;tb:TaskbarIcon.DataContext&amp;gt;
            &amp;lt;robot:SysTrayViewModel /&amp;gt;
        &amp;lt;/tb:TaskbarIcon.DataContext&amp;gt;
    &amp;lt;/tb:TaskbarIcon&amp;gt;

&amp;lt;/ResourceDictionary&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;Как видно из кода пункты контекстного меню вызывают функции ShowWindowCommand/HideWindowCommand/ExitApplicationCommand, которые расположены в классе SysTrayViewModel. &lt;br /&gt;&lt;br /&gt;2) данный словарь необходимо вызвать из App.xaml, что объект отрисовался сразу после запуска программы&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

    &amp;lt;Application.Resources&amp;gt;
        &amp;lt;ResourceDictionary&amp;gt;
            &amp;lt;ResourceDictionary.MergedDictionaries&amp;gt;
                &amp;lt;ResourceDictionary Source=&amp;quot;Service\SysTrayResources.xaml&amp;quot; /&amp;gt;
            &amp;lt;/ResourceDictionary.MergedDictionaries&amp;gt;
        &amp;lt;/ResourceDictionary&amp;gt;
    &amp;lt;/Application.Resources&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;3) далее создаем класс SysTrayViewModel, в котором размешаем команды скрытия/отображения робота:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

    public class SysTrayViewModel
    {

        public ICommand ShowWindowCommand
        {
            get
            {
                return new DelegateCommand
                {
                    CanExecuteFunc = () =&amp;gt; Application.Current.MainWindow.Visibility == Visibility.Hidden,
                    CommandAction = () =&amp;gt;
                    {
                   if (Application.Current.MainWindow == null) Application.Current.MainWindow = new MainWindow();
                   else Application.Current.MainWindow.Visibility = Visibility.Visible;
                    }
                };
            }
        }

        public ICommand HideWindowCommand
        {
            get
            {
                return new DelegateCommand
                {
                    CommandAction = () =&amp;gt; Application.Current.MainWindow.Visibility = Visibility.Hidden,
                    CanExecuteFunc = () =&amp;gt; Application.Current.MainWindow.Visibility == Visibility.Visible
                };
            }
        }

        public ICommand ExitApplicationCommand
        {
            get
            {
                return new DelegateCommand { CommandAction = () =&amp;gt; Application.Current.Shutdown() };
            }
        }
    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;При этом нужно пояснить что DelegateCommand - это класс-делегат для ускоренного создания выполняемых команд&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

    public class DelegateCommand : ICommand
    {
        public Action CommandAction { get; set; }
        public Func&amp;lt;bool&amp;gt; CanExecuteFunc { get; set; }

        public void Execute(object parameter)
        {
            CommandAction();
        }

        public bool CanExecute(object parameter)
        {
            return CanExecuteFunc == null || CanExecuteFunc();
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Итак - контекстное меню прекрасно работает.&lt;br /&gt;Но этого мало))&lt;br /&gt;&lt;br /&gt;4) Создаем в настройках свойство Starthide, и помещаем в процедуру MainWindow() простую проверку на необходимость сразу скрыть робота после старта:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

            if (SettingsEngine.Instance.Properties.Starthide)
                Application.Current.MainWindow.Visibility = Visibility.Hidden;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;5) Ставим для отображения робота ПАРОЛЬ - как же без него!&lt;br /&gt;Для этого создаем маленькую пользовательскую форму UIpassword, в которой размещает поле для вода текста типа PasswordBox&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

    &amp;lt;Grid &amp;gt;
        &amp;lt;PasswordBox Name=&amp;quot;pwdBox&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; Margin=&amp;quot;17,20,0,0&amp;quot; VerticalAlignment=&amp;quot;Top&amp;quot; Width=&amp;quot;145&amp;quot; 
                     PasswordChar=&amp;quot;#&amp;quot; PasswordChanged=&amp;quot;PasswordChangedHandler&amp;quot; Height=&amp;quot;29&amp;quot;/&amp;gt;
        &amp;lt;Label Content=&amp;quot;Password please&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; Height=&amp;quot;24&amp;quot; Margin=&amp;quot;38,-4,0,0&amp;quot; VerticalAlignment=&amp;quot;Top&amp;quot; Width=&amp;quot;102&amp;quot;/&amp;gt;

    &amp;lt;/Grid&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;В событии PasswordChangedHandler прописываем проверку заданного нами пароля и если все ок - то отображаем основное окно робота&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

        private void PasswordChangedHandler(object sender, RoutedEventArgs e)
        {
            //Debug.WriteLine(pwdBox.Password);
            if (pwdBox.Password == &amp;quot;ххххххх&amp;quot;)
            {
                Application.Current.MainWindow.Visibility = Visibility.Visible;
            }
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;И после этого в коде класса SysTrayViewModel вместо мгновенного открытия приложения прописываем старт формы UIpassword&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

           CommandAction = () =&amp;gt;
            {
              if (Application.Current.MainWindow == null) Application.Current.MainWindow = new MainWindow();
              var newWnd = new UIpassword();
              newWnd.ShowDialog();
            }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/31207/</id>
    <title type="text">Часть 9 - Проходим АД AdoNeta, или о сохранении параметров в базе данных Как известно, в базовой вер...</title>
    <published>2014-07-15T19:09:29Z</published>
    <updated>2014-07-15T19:39:50Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">&lt;b&gt;Часть 9 - Проходим АД AdoNeta, или о сохранении параметров в базе данных&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Как известно, в базовой версии S#.Shell отсутствует функционал, позволяющий восстановить позиции после перезапуска робота. &lt;br /&gt;В версии от КазайМазай был предложен метод сохранения в xml-файл через набор свойств базовой стратегии (OrdersByTransactionId, SecuritiesByTransactionId, TradesByTransactionId, PortfoliosByTransactionId, ExchangesByTransactionId) типа SettingsStorage.&lt;br /&gt;При этом у меня при всех старании активировать данное сохранение, данный метод не заработал - при активации RestorePositionsOnStart записанные теги оказывались пустыми.&lt;br /&gt;На форуме так же описан метод сохранения ордеров в txt-файл, который судя по простоте работает.&lt;br /&gt;&lt;br /&gt;Но все же сохранение в файл при всей простоте восстановления позиций такого важного элемента в созхранении записей как ведение управленческого учета прибылей и убытков от работы робота.&lt;br /&gt;&lt;br /&gt;Именно по  этой причине целесообразно реализовать функционал сохранения истории торгов в базу данных (MSSQLSRV, MSACCESS, SQLLITE и пр.) - гибкость в последобработке данной информации позволяет автоматизировать ведение учета результатов торгов.&lt;br /&gt;&lt;br /&gt;Рассмотрим реализацию сохранения состояния робота в базу данных основе AdoNet.&lt;br /&gt;&lt;br /&gt;1. Создадим базовый класс StorageEngine&lt;br /&gt;Данный класс будет хранить обертки для подключений. По умолчанию программируем только для одного вида базы данных - MSSQLSRV, хотя при дальнейшей проработки данного класса его можно сделать универсальным провайдером функций для работы с любым выбранным пользователем видом базы данных, для которого есть драйвера AdoNet (MSSQLSRV, MSACCESS, SQLLITE) &lt;br /&gt; &lt;br /&gt;а) функция инициализации будет содержать переменную по проверке готовности БД IsVerified, а так же вызов заданных пользователем параметров:  curStor - вид базы данных, ShellConfigDB - название каталога MSSQLSRV (файла для MSACCESS и SQLLITE)&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        private StorageEngine()
		{
            Name = &amp;quot;StorageEngine&amp;quot;;
            IsVerified = false;
            ShellConfigDB = SettingsEngine.Instance.Properties.ShellConfigDB;
            curStor = SettingsEngine.Instance.Properties.DataStorIn;
		}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;б)  переменные для хранения универсальных команд создания базовых таблиц (tblOrders - таблица заявок, tblTrades  - таблица сделок), добавления данных и удаления данных из этих таблиц&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        public const string CreateOrders = @&amp;quot;CREATE TABLE tblOrders &amp;quot; +
                                            &amp;quot;(StrategyId varchar(50), &amp;quot; +
                                            &amp;quot;TransactionId INT, &amp;quot; +
                                            &amp;quot;OrdId BIGINT, &amp;quot; +
                                            &amp;quot;Direction varchar(4), &amp;quot; +
                                            &amp;quot;Type varchar(10), &amp;quot; +
                                            &amp;quot;ExpiryDate date, &amp;quot; +
                                            &amp;quot;State varchar(10), &amp;quot; +
                                            &amp;quot;Status varchar(10), &amp;quot; +
                                            &amp;quot;Security varchar(20), &amp;quot; +
                                            &amp;quot;ExBoard varchar(10), &amp;quot; +
                                            &amp;quot;Portfolio varchar(10), &amp;quot; +
                                            &amp;quot;Price FLOAT, &amp;quot; +
                                            &amp;quot;Time datetime , &amp;quot; +
                                            &amp;quot;Volume int , &amp;quot; +
                                            &amp;quot;Comment varchar(50))&amp;quot;;

        public const string CreateTrades = @&amp;quot;CREATE TABLE tblTrades &amp;quot; +
                                            &amp;quot;(StrategyId varchar(50), &amp;quot; +
                                            &amp;quot;TransactionId int , &amp;quot; +
                                            &amp;quot;TradeId int, &amp;quot; +
                                            &amp;quot;Price float, &amp;quot; +
                                            &amp;quot;Time datetime, &amp;quot; +
                                            &amp;quot;Volume int)&amp;quot;;

        public const string SelectOrders =
                 @&amp;quot;SELECT StrategyId, OrdId, TransactionId, Direction, Type, ExpiryDate, State, Status, 
                   Security, ExBoard, Portfolio, Price, Time, Volume, Comment &amp;quot; +
                  @&amp;quot;FROM tblOrders WHERE StrategyId=@SID&amp;quot;;

        public const string DeleteOrders =
            @&amp;quot;DELETE FROM tblOrders WHERE StrategyId=@SID&amp;quot;;

        public const string SelectTrades =
            @&amp;quot;SELECT StrategyId, TransactionId, TradeId, Price, Time, Volume &amp;quot; +
            @&amp;quot;FROM tblTrades WHERE StrategyId=@SID and TransactionId=@TID&amp;quot;;

        public const string DeleteTrades =
            @&amp;quot;DELETE FROM tblTrades WHERE StrategyId=@SID&amp;quot;;

&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;в) создадим  ряд оберток для различных функций по работе с базами данных: в данном случае функции возвращают  MSSQLSRV- специфичные объекты, и не являются универсальными обертками, но принцип ясен&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;


        public SqlConnection GetConnection()
        {
            SqlConnectionStringBuilder sqlConStr = new SqlConnectionStringBuilder();
            sqlConStr.DataSource = @&amp;quot;(local)&amp;quot;;
            sqlConStr.IntegratedSecurity = true;
            sqlConStr.InitialCatalog = ShellConfigDB;
            SqlConnection result = new SqlConnection(sqlConStr.ConnectionString);
            return result;
        }

        public SqlDataAdapter OpenData()
        {
            SqlDataAdapter da1 = new SqlDataAdapter();
            return da1;
        }

        public SqlCommand SqlCmd(string sqlScmd, DbConnection sqlCon)
        {
            SqlCommand cmd1 = new SqlCommand(sqlScmd, (SqlConnection)sqlCon);
            return cmd1;
        }

        public SqlCommandBuilder BuildCmd(DbDataAdapter da)
        {
            SqlCommandBuilder cb1 = new SqlCommandBuilder((SqlDataAdapter)da);
            return cb1;
        }

&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;г) создадим функцию VerifyStor, которая  будет вызываться при первичном обращении к классу для проверки готовности БД к приему данных, если БД не готова - отсутствуют таблицы, то автоматом создаются новые структуры:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        public void VerifyStor()
        {
            if (IsVerified) return;

            switch (curStor)
            {
                case SettingsProperties.DataStorType.MSSQLSRV:

                    SqlConnection sqlCon = GetConnection();
                    sqlCon.Open();
                    if (sqlCon.State != ConnectionState.Open)
                    {
                        MessageBox.Show(&amp;quot;Подключение завершилось с ошибкой&amp;quot;);
                        return;
                    }

                    var sqlStr = @&amp;quot;SELECT count(name)  FROM [ShellAdvanced].[sys].[tables] where name = &amp;#39;tblOrders&amp;#39;&amp;quot;;
                    SqlCommand sqlCmd = new SqlCommand(sqlStr, sqlCon);
                    int rowCount = (int) sqlCmd.ExecuteScalar();
                    sqlCmd.Dispose();

                    if (rowCount == 0)
                    {
                        SqlCommand sqlCmd1 = new SqlCommand(CreateOrders, sqlCon);
                        sqlCmd1.ExecuteNonQuery();
                        sqlCmd1.Dispose();

                        SqlCommand sqlCmd2 = new SqlCommand(CreateTrades, sqlCon);
                        sqlCmd2.ExecuteNonQuery();
                        sqlCmd2.Dispose();

                        SqlCommand sqlCmd3 = new SqlCommand(CreateBook, sqlCon);
                        sqlCmd3.ExecuteNonQuery();
                        sqlCmd3.Dispose();

                    }
                    sqlCon.Close();
                    break;
                 
            }

            IsVerified = true;
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;При этом конструкция if (IsVerified) return; позволяет минимизировать время проверки за счет сохранения статуса &amp;quot;Проверено&amp;quot; в свойстве IsVerified.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. Для однозначной идентификации сохраненной стратегии используем Strategy.Id - свойство типа GUID, которое генерится автоматически при создании новой стратегии и в силу алгоритма генерации GUID позволяет фактически уникально определить стратегию.&lt;br /&gt;&lt;br /&gt;а) в свойства добавляем поле StrategyID для сохранения GUID в текстовом виде&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;


        private string _StrategyID;

        [DisplayName(@&amp;quot;Strategy ID&amp;quot;)]
        [Description(@&amp;quot;Уникальный идентификатор стратегии&amp;quot;)]
        [Category(@&amp;quot;Основные&amp;quot;)]
        [PropertyOrder(7)]
        public string StrategyID
        {
            get { return _StrategyID; }
            set
            {
                _StrategyID = value;
                OnPropertyChanged(&amp;quot;StrategyID&amp;quot;);
            }
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;б) вносим восстановление GUID в различные функции создания стратегий а-ля AddRobotStrategy/AddRobotTestStrategy в классе MainWindow:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            if (properties.StrategyID != null)
                strategy.Id = new Guid(properties.StrategyID);
            else
                properties.StrategyID = strategy.Id.ToString();
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;3. Теперь напишем функции сохранения и загрузки заявок/сделок из MSSQLSRV, разместив их в классе SettingsEngine&lt;br /&gt;&lt;br /&gt;а) функция SaveToDB(Strategy str) принимает на вход стратегию, сделки и заявки которой необходимо сохранить&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;


public void SaveToDB(Strategy str)
	    {

            SqlDataAdapter sqlDa;
            DataTable dataTable;
	        SqlCommand sqlSCmd; // Select command
            SqlCommand sqlICmd; // Insert command
            SqlCommand sqlDCmd; // Delete commend
	        SqlCommandBuilder sqlCMDB;

            StorageEngine.Instance.VerifyStor(); // Проверка базы


            var sqlCon = StorageEngine.Instance.GetConnection();

            // Сохраняем сделки
                var sid = str.Id.ToString();
                var qrOrders = from r in str.MyTrades
                               select
                                   new
                                   {   StriD = sid,
                                       TID = r.Order.TransactionId,
                                       OrdId = r.Order.Id,
                                       OrdDir = r.Order.Direction.ToString(),
                                       OrdType = r.Order.Type.ToString(),
                                       r.Order.ExpiryDate,
                                       OrdState = r.Order.State.ToString(),
                                       OrdStatus = r.Order.Status.ToString(),
                                       SecId = r.Order.Security.Id,
                                       SecExch = r.Order.Security.Board.Code,
                                       Portname = r.Order.Portfolio.Name,
                                       r.Order.Price,
                                       r.Order.LastChangeTime,
                                       r.Order.Volume,
                                       r.Order.Comment
                                   };

                if (qrOrders.Count()==0) return;

                sqlDa = StorageEngine.Instance.OpenData();
                sqlSCmd = StorageEngine.Instance.SqlCmd(StorageEngine.SelectOrders, sqlCon);
                sqlSCmd.Parameters.AddWithValue(&amp;quot;@SID&amp;quot;, sid);
	            sqlDa.SelectCommand = sqlSCmd;

                sqlCMDB = StorageEngine.Instance.BuildCmd(sqlDa);
                sqlICmd = sqlCMDB.GetInsertCommand();

                dataTable = new DataTable();
                sqlDa.Fill(dataTable);

                sqlCon.Open();
                sqlDCmd = StorageEngine.Instance.SqlCmd(StorageEngine.DeleteOrders, sqlCon);
                sqlDCmd.Parameters.AddWithValue(&amp;quot;@SID&amp;quot;, sid);
                sqlDCmd.ExecuteNonQuery();
                sqlCon.Close();

                foreach (var qrOrder in qrOrders)
                {
                    DataRow rw = dataTable.NewRow();
                    rw[&amp;quot;StrategyId&amp;quot;] = qrOrder.StriD;
                    rw[&amp;quot;TransactionId&amp;quot;] = qrOrder.TID;
                    rw[&amp;quot;OrdId&amp;quot;] = qrOrder.OrdId;
                    rw[&amp;quot;Direction&amp;quot;] = qrOrder.OrdDir;
                    rw[&amp;quot;Type&amp;quot;] = qrOrder.OrdType;
                    rw[&amp;quot;ExpiryDate&amp;quot;] = qrOrder.ExpiryDate;
                    rw[&amp;quot;State&amp;quot;] = qrOrder.OrdState;
                    rw[&amp;quot;Status&amp;quot;] = qrOrder.OrdStatus;
                    rw[&amp;quot;Security&amp;quot;] = qrOrder.SecId;
                    rw[&amp;quot;ExBoard&amp;quot;] = qrOrder.SecExch;
                    rw[&amp;quot;Portfolio&amp;quot;] = qrOrder.Portname;
                    rw[&amp;quot;Price&amp;quot;] = qrOrder.Price;
                    rw[&amp;quot;Time&amp;quot;] = qrOrder.LastChangeTime;
                    rw[&amp;quot;Volume&amp;quot;] = qrOrder.Volume;
                    rw[&amp;quot;Comment&amp;quot;] = qrOrder.Comment;
                    dataTable.Rows.Add(rw);
                }
                var cnt = sqlDa.Update(dataTable);
                str.AddInfoLog(&amp;quot;В базу сохранено {0} заявок&amp;quot;, cnt);
                
                dataTable.Dispose();

                // Запись сделок
                var qrTrades = from tr in str.MyTrades
                               select
                                   new
                                   {   StrId = sid,
                                       TID = tr.Order.TransactionId,
                                       tr.Trade.Id,
                                       tr.Trade.Price,
                                       tr.Trade.Time,
                                       tr.Trade.Volume};

                sqlDa = StorageEngine.Instance.OpenData();
                sqlSCmd = StorageEngine.Instance.SqlCmd(StorageEngine.SelectTrades, sqlCon);
                sqlSCmd.Parameters.AddWithValue(&amp;quot;@SID&amp;quot;, sid);
                sqlSCmd.Parameters.AddWithValue(&amp;quot;@TID&amp;quot;, &amp;quot;&amp;quot;);
                sqlDa.SelectCommand = sqlSCmd;

                sqlCMDB = StorageEngine.Instance.BuildCmd(sqlDa);
                sqlICmd = sqlCMDB.GetInsertCommand();

                dataTable = new DataTable();
                sqlDa.Fill(dataTable);
                
                // Удаляем старые записи
                sqlCon.Open();
                sqlDCmd = StorageEngine.Instance.SqlCmd(StorageEngine.DeleteTrades, sqlCon);
                sqlDCmd.Parameters.AddWithValue(&amp;quot;@SID&amp;quot;, sid);
                sqlDCmd.ExecuteNonQuery();
                sqlCon.Close();

                foreach (var qrTrade in qrTrades)
                {
                    DataRow rw = dataTable.NewRow();
                    rw[&amp;quot;StrategyId&amp;quot;] = qrTrade.StrId;
                    rw[&amp;quot;TransactionId&amp;quot;] = qrTrade.TID;
                    rw[&amp;quot;TradeId&amp;quot;] = qrTrade.Id;
                    rw[&amp;quot;Price&amp;quot;] = qrTrade.Price;
                    rw[&amp;quot;Time&amp;quot;] = qrTrade.Time;
                    rw[&amp;quot;Volume&amp;quot;] = qrTrade.Volume;
                    dataTable.Rows.Add(rw);
                }
                var cntn = sqlDa.Update(dataTable);

                str.AddInfoLog(&amp;quot;В базу сохранено {0} сделок&amp;quot;, cntn);         
                
	    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;б) функция LoadFromDB (Strategy str) принимает на вход стратегию, сделки и заявки которой необходимо загрузить &lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

	    public void LoadFromDB(Strategy str)
          {

            var sqlCon = StorageEngine.Instance.GetConnection();
            SqlDataAdapter sqlDa;
            SqlCommand sqlSCmd; // Select command
            DataTable TableOrders = new DataTable();
            DataTable TableTrades = new DataTable();
            DataTable TableBook = new DataTable();


                var sid = str.Id.ToString();
                sqlDa = StorageEngine.Instance.OpenData();
                sqlSCmd = StorageEngine.Instance.SqlCmd(StorageEngine.SelectOrders, sqlCon);
	            sqlSCmd.Parameters.AddWithValue(&amp;quot;@SID&amp;quot;, sid);
                sqlDa.SelectCommand = sqlSCmd;
                sqlDa.Fill(TableOrders);

                str.AddInfoLog(&amp;quot;Из базы загружено {0} заявок&amp;quot;, TableOrders.Rows.Count.ToString());    
	            if (TableOrders.Rows.Count == 0) return;
                
                foreach (DataRow rw in TableOrders.Rows)
                {
                    long tid = (int)rw[&amp;quot;TransactionId&amp;quot;];
                    var order = new Order() { TransactionId = tid };
                    long oid = (long)rw[&amp;quot;OrdId&amp;quot;];
                    order.Id = oid;
	                if (order != null)
	                {
	                    order.Connector = str.Connector;
	                    var security = new Security() {Id = (string) rw[&amp;quot;Security&amp;quot;]};
	                    if (security != null)
	                    {
	                        var exchange = new ExchangeBoard() {Code = (string)rw[&amp;quot;ExBoard&amp;quot;]};
	                        if (exchange != null) 
                                security.Board = exchange;
	
                            security.Connector = str.Connector;
	                        order.Security = security;
	                    }
                        
                        OrderTypes OrdType;
                        OrderTypes.TryParse((string)rw[&amp;quot;Type&amp;quot;], out OrdType);
                        order.Type = OrdType;

                        Sides OrderDir;
                        Sides.TryParse((string)rw[&amp;quot;Direction&amp;quot;], out OrderDir);
                        order.Direction = OrderDir;

                        OrderStates OrdState;
                        OrderStates.TryParse((string)rw[&amp;quot;State&amp;quot;],out OrdState);
	                    order.State = OrdState;

	                    order.Portfolio = new Portfolio() {Name = (string)rw[&amp;quot;Portfolio&amp;quot;]};
                        order.ExpiryDate = (DateTime)rw[&amp;quot;ExpiryDate&amp;quot;];
	                    order.Price = (decimal)(double)rw[&amp;quot;Price&amp;quot;];
                        order.Volume = (decimal)(int)rw[&amp;quot;Volume&amp;quot;];
                        order.Time = (DateTime)rw[&amp;quot;Time&amp;quot;];
                        order.LastChangeTime = (DateTime)rw[&amp;quot;Time&amp;quot;];
                        if (! DBNull.Value.Equals(rw[&amp;quot;Comment&amp;quot;]))
                            { order.Comment = (string)rw[&amp;quot;Comment&amp;quot;]; } // DBNUll to String

                        var myTrades = new List&amp;lt;MyTrade&amp;gt;(); // Все сделки по заявке с номером tid
                        sqlSCmd = StorageEngine.Instance.SqlCmd(StorageEngine.SelectTrades, sqlCon);
                        sqlSCmd.Parameters.AddWithValue(&amp;quot;@SID&amp;quot;, sid);
                        sqlSCmd.Parameters.AddWithValue(&amp;quot;@TID&amp;quot;, tid);
                        var sqlTDa = StorageEngine.Instance.OpenData();
                        sqlDa.SelectCommand = sqlSCmd;
                        sqlDa.Fill(TableTrades);

                        foreach (DataRow tr in TableTrades.Rows)
	                     {
                                var myTrade = new MyTrade(); 
	                            myTrade.Order = order;
                                var thisTrade = new Trade() { Id = (long)(int)tr[&amp;quot;TradeId&amp;quot;], Price = (decimal)(double)tr[&amp;quot;Price&amp;quot;], Time = (DateTime)tr[&amp;quot;Time&amp;quot;], Volume = (decimal)(int)tr[&amp;quot;Volume&amp;quot;] };
                                myTrade.Trade = thisTrade;
	                            myTrade.Trade.OrderDirection = order.Direction;
                                myTrade.Trade.Security = security;
	                            myTrade.Trade.Status = 0;
	                            myTrades.Add(myTrade);

	                        }

	                    try
	                    {
                            str.AttachOrder(order, myTrades);
	                    }
	                    catch (Exception ex)
	                    {
	                          Debug.WriteLine(ex.Message);
	                    }
                        TableTrades.Clear();   

                    }
                }
                TableOrders.Dispose();
                TableTrades.Dispose();          	               

            
	    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;в) тут же создаем универсальный загрузчик заявок и сделок на панели тестового документа, который как научились в Части 8 использовать как для тестовых прогонов, так и для реального запуска робота.&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        public void AddHistOrdersPane(TestingDocument doc)
        {
            Strategy str = doc.Strategy;

            var _myOrders = doc.TestingPanel.myOrders;
            _myOrders.Orders.AddRange(str.Orders);

            var _myTrades = doc.TestingPanel.myTrades;
            _myTrades.Trades.AddRange(str.MyTrades);
	    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;4. Вызываем из нужных мест функции SaveToDB/LoadFromDB&lt;br /&gt;&lt;br /&gt;а) запиливаем вызов SaveToDB в функцию SaveStrategies, проверяя при этом наличие в параметрах стратегии установленного свойства RestorePositionsOnStart&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

                    var StrToSave = _documents.Keys.Where(str =&amp;gt; str.Params.RestorePositionsOnStart).ToList();
                    foreach (BaseShellStrategy strategy in StrToSave )
		                SettingsEngine.Instance.SaveToDB(strategy );
		           
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;б) аналогично запаиваем вызов SaveToDB в правила WhenOrderRegistered / WhenNewMyTrades&lt;br /&gt;&lt;br /&gt;в) запихиваем вызов LoadFromDB в различные функции создания стратегий а-ля AddRobotStrategy/AddRobotTestStrategy в классе MainWindow:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            if (strategy.Params.RestorePositionsOnStart) SettingsEngine.Instance.LoadFromDB(strategy);
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. Последний штрих - создаем в параметрах S#.Shell (класс SettingsProperties) свойства для сохранения переменных curStor - вид базы данных, ShellConfigDB - название каталога MSSQLSRV (файла для MSACCESS и SQLLITE)&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;
 
         public enum DataStorType {SQLLITE,MSSQLSRV}

        private DataStorType _dataStor;
        [Category(@&amp;quot;Сохранение&amp;quot;)]
        [DisplayName(@&amp;quot;База данных&amp;quot;)]
        [Description(@&amp;quot;Вариант сохранения данных&amp;quot;)]
        [PropertyOrder(1)]
        public DataStorType DataStorIn
        {
            get { return _dataStor; }
            set
            {
                _dataStor = value;
                OnPropertyChanged(&amp;quot;DataStorIn&amp;quot;);
            }
        }

        private string _ShellConfigDB;
        [Category(@&amp;quot;Сохранение&amp;quot;)]
        [DisplayName(@&amp;quot;Название базы&amp;quot;)]
        [Description(@&amp;quot;Название базы данных или имя файла&amp;quot;)]
        [PropertyOrder(2)]
        public string ShellConfigDB
        {
            get { return _ShellConfigDB; }
            set
            {
                _ShellConfigDB = value;
                OnPropertyChanged(&amp;quot;ShellConfigDB&amp;quot;);
            }
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;И вуаля - сохранение в базу MSSQLSRV работает как часы!&lt;br /&gt;Выглядит все просто, но чтобы пройти реально этот Ад, мне потребовалось 2 месяца арбайтена и штудирена))&lt;br /&gt;&lt;br /&gt;Аналогично можно сохранять любые другие свойства стратегии, например PnL. Хотя тут я пошел другим путем и сделал динамическое восстановление PnL из сохраненных сделок.</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/30720/</id>
    <title type="text">Часть 8 - Универсализация интерфейсов исполнения стратегий Сделаем еще один шаг к раз0витию S#.Shell...</title>
    <published>2014-06-15T13:35:21Z</published>
    <updated>2014-06-15T14:11:10Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">&lt;b&gt;Часть 8 - Универсализация интерфейсов исполнения стратегий &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Сделаем еще один шаг к раз0витию S#.Shell - проведем универсализацию интерфейсов исполнения.&lt;br /&gt;Как известно в стандартной версии S#.Shell тестовые стратегии выполняются на панеле (документе), где присутствуют графики и где можно добавить собственные панели (см. Часть 5), а исполнение на живом подключении проводится на панеле с сокращенным набором элементов.&lt;br /&gt;Это не всегда удобно. Да и для новых стратегий тоже важно в первые месяцы их жизни следить за их состоянием с использованием графических элементов.&lt;br /&gt;&lt;br /&gt;Для решения этой задачи вначале разбираемся как в В S#.Shell создаются панели.&lt;br /&gt;Панель это на самом деле объект типа LayoutDocument из библиотеки AvalonDock, в котором можно задавать различный контент путем присвоения свойства Content типа object. &lt;br /&gt;При этом в свойство Content записывается пользовательский элемент управления типа UserControl, графические элементы которого и определяют расположение и набор элементов.&lt;br /&gt;Исполняемая стратегия у данного элемент управления это всего лишь свойство типа BaseShellStrategy, которое очевидно может выполняться в любом режиме - как тестовом, так и боевом.&lt;br /&gt;&lt;br /&gt;С учетом этого для получения возможности запускать стратегии с любым типом панели делаем следующие вещи:&lt;br /&gt; &lt;br /&gt;1. Создаем в свойствах стратегии BaseShellStrategyPropeties признак , который указываем на каком виде документа выполняется стратегия:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

        private enDocType _doctype = enDocType.TestDoc;
        [Category(@&amp;quot;Основные&amp;quot;)]
        [DisplayName(@&amp;quot;Тип документа&amp;quot;)]
        [Description(@&amp;quot;Тип документа стратегии&amp;quot;)]
        [PropertyOrder(2)]
        public enDocType DocType
        {
            get { return _doctype; }
            set
            {
                _doctype = value;
                OnPropertyChanged(&amp;quot;DocType&amp;quot;);
            }
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;При этом enDocType задаем как перечисляемый тип&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

    public enum enDocType
    {
        TestDoc,
        ExecDoc
    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;2. В классе MainWindow во всех процедурах типа ExecutedAddХХХХStrategy создания исполняемых стратегий, в которых мы хотим получить выбор типа документа исполнения, задаем возможность указать желаемый вид документа:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

            DialogResult result;
            string selectstr = &amp;quot;Тип документа: сокращенный(Y) или полный(N)?&amp;quot;;
            result = System.Windows.Forms.MessageBox.Show(selectstr, &amp;quot;Выбор типа документа&amp;quot;, MessageBoxButtons.YesNo);
            if (result == System.Windows.Forms.DialogResult.Yes)
                properties.DocType = enDocType.ExecDoc;
            else
                properties.DocType = enDocType.TestDoc;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;3. Далее классе MainWindow в связанных процедурах создания стратегий модифицируем создание LayoutDocument, используя указанный признак для присвоения желаемого типа документа&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

            LayoutDocument doc=new LayoutDocument();
            doc.Content = docType == enDocType.ExecDoc? (object) new StrategyDocument {Strategy = strategy}: new TestingDocument {Strategy = strategy};
            doc.Title = strategy.Params.Name;
            doc.CanClose = false;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;4. Из процедуры StartTesingStrategy выводим весь код по инициализации графических панелей в отдельную процедуру InitializePanes, которую затем безу3словно вызываем из StartTesingStrategy  и условино вызываем из процедуры StartStrategy:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:c-sharp"&gt;

if (_strategy.Params.Mode == enMode.Testing)
{
            Action InitPanes = null;
		    InitPanes = () =&amp;gt;
                    {
                        var doc = SelectedTestingDocument;
                        InitializePanes(doc);
		     };

		    if (dockManager.Dispatcher.CheckAccess())
		        InitPanes();
		    else
		        dockManager.Dispatcher.BeginInvoke(DispatcherPriority.Normal, InitPanes);
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;Причем по каким-то причинам в случае прямого вызова InitializePanes(doc) при исполнении стратегии происходят ошибки связанные с пересечением потоков, поэтому как в приведенном выше коде использовалась лямбда-функция InitPanes, которая получает тестовый документ через SelectedTestingDocument и вызывввается в потокобезопасном режиме.&lt;br /&gt;&lt;br /&gt;И вот все готово!</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/30326/</id>
    <title type="text">Итак в целом миграция завершена. Нужно признать что кода в StockSharp получилось гораздо больше, чем...</title>
    <published>2014-04-14T15:38:59Z</published>
    <updated>2014-06-15T13:14:22Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">Итак в целом миграция завершена. Нужно признать что кода в StockSharp получилось гораздо больше, чем Tradematic - раза в три больше.&lt;br /&gt;Но тут как раз и пора показать основное преимущество StockSharp - открытость кода для создания пользователького интерфейса управления работающей стратегией.&lt;br /&gt;&lt;br /&gt;6) Создаем элементы для визуализации кастомарных свойств новой стратегии&lt;br /&gt;а) вначале создаем StrategyPlanDG для привязки Плана торговли&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:xml"&gt;

&amp;lt;Grid DataContext=&amp;quot;{Binding RelativeSource={RelativeSource Self}}&amp;quot; &amp;gt;
        &amp;lt;DataGrid Name=&amp;quot;PlanDG&amp;quot; AutoGenerateColumns=&amp;quot;False&amp;quot; IsReadOnly=&amp;quot;False&amp;quot; &amp;gt;
                &amp;lt;DataGrid.Columns&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;30&amp;quot;  Header=&amp;quot;Id&amp;quot; Binding=&amp;quot;{Binding Path=Id}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot; /&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;80&amp;quot;  Header=&amp;quot;Сигнал&amp;quot; Binding=&amp;quot;{Binding Path=SignalName}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot;/&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;Покупка&amp;quot; Binding=&amp;quot;{Binding Path=PlanPrice, StringFormat=N0}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot;/&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;Продажа&amp;quot; Binding=&amp;quot;{Binding Path=SellPrice, StringFormat=N0}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot; /&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;60&amp;quot;  Header=&amp;quot;Объем&amp;quot; Binding=&amp;quot;{Binding Path=Amount, ValidatesOnExceptions=True,  StringFormat=F0}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot; /&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;60&amp;quot; Header=&amp;quot;Прибыль&amp;quot; Binding=&amp;quot;{Binding Path=LevelGain, StringFormat=P2}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot; /&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;CapShort&amp;quot; Binding=&amp;quot;{Binding Path=CapShort,StringFormat=N0}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot; /&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;CapShort%&amp;quot; Binding=&amp;quot;{Binding Path=CapShortPcn,StringFormat=P2}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot; /&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;CapLong&amp;quot; Binding=&amp;quot;{Binding Path=CapLong,StringFormat=N0}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot; /&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;CapLong%&amp;quot; Binding=&amp;quot;{Binding Path=CapLongPcn,StringFormat=P2}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot; /&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;100&amp;quot; Header=&amp;quot;Посл.покупка&amp;quot; Binding=&amp;quot;{Binding Path=BuyDate, StringFormat=&amp;#39;dd.MM.yy HH:mm&amp;#39;}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot;/&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;60&amp;quot;  Header=&amp;quot;Позиция&amp;quot; Binding=&amp;quot;{Binding Path=Vol, Mode=TwoWay, StringFormat=N0}&amp;quot; /&amp;gt;
                &amp;lt;DataGridTextColumn Width=&amp;quot;100&amp;quot; Header=&amp;quot;Посл.продажа&amp;quot; Binding=&amp;quot;{Binding Path=SellDate, StringFormat=&amp;#39;dd.MM.yy HH:mm&amp;#39;}&amp;quot; IsReadOnly=&amp;quot;True&amp;quot;/&amp;gt;
            &amp;lt;/DataGrid.Columns&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt; &lt;br /&gt;и выводим его на вкладку в элементе TestingPanel стандартного интерфейса S#.Shell + &lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:xml"&gt;
 
                &amp;lt;TabItem x:Name=&amp;quot;TabPlan&amp;quot; Header=&amp;quot;Plan&amp;quot; Visibility=&amp;quot;Hidden&amp;quot;&amp;gt;
                    &amp;lt;Grid&amp;gt;
                        &amp;lt;Grid.RowDefinitions&amp;gt;
                            &amp;lt;RowDefinition Height=&amp;quot;25&amp;quot;&amp;gt;&amp;lt;/RowDefinition&amp;gt;
                            &amp;lt;RowDefinition Height=&amp;quot;25&amp;quot;&amp;gt;&amp;lt;/RowDefinition&amp;gt;
                            &amp;lt;RowDefinition Height=&amp;quot;*&amp;quot;&amp;gt;&amp;lt;/RowDefinition&amp;gt;
                        &amp;lt;/Grid.RowDefinitions&amp;gt;
                        &amp;lt;DockPanel&amp;gt;
                            &amp;lt;Button x:Name=&amp;quot;btnCalc&amp;quot; Width=&amp;quot;80&amp;quot; Content=&amp;quot;Create&amp;quot; Click=&amp;quot;BtnCalc_OnClick&amp;quot; Margin=&amp;quot;10,5,0,0&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; &amp;gt;&amp;lt;/Button&amp;gt;
                            &amp;lt;Button x:Name=&amp;quot;btnFill&amp;quot; Width=&amp;quot;80&amp;quot; Content=&amp;quot;Fill&amp;quot; Click=&amp;quot;BtnFill_OnClick&amp;quot; Margin=&amp;quot;10,5,0,0&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; /&amp;gt;
                            &amp;lt;Button x:Name=&amp;quot;btnRecalc&amp;quot; Width=&amp;quot;80&amp;quot; Content=&amp;quot;Usage&amp;quot; Click=&amp;quot;BtnRecalc_OnClick&amp;quot; Margin=&amp;quot;10,5,0,0&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; /&amp;gt;
                        &amp;lt;/DockPanel&amp;gt;
                        &amp;lt;DockPanel x:Name=&amp;quot;CapitalInfo&amp;quot; Grid.Row=&amp;quot;1&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot;&amp;gt;
                            &amp;lt;Label Content=&amp;quot;Уровней&amp;quot; Width=&amp;quot;60&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; /&amp;gt;
                            &amp;lt;TextBlock x:Name=&amp;quot;nbins&amp;quot; Width=&amp;quot;40&amp;quot; Text=&amp;quot;{Binding Path=NBins}&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; VerticalAlignment=&amp;quot;Center&amp;quot; /&amp;gt;
                            &amp;lt;Label Content=&amp;quot;Cap Short&amp;quot; Width=&amp;quot;70&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; /&amp;gt;
                            &amp;lt;TextBlock x:Name=&amp;quot;shortVal&amp;quot; Width=&amp;quot;60&amp;quot; Text=&amp;quot;{Binding Path=ShortCapVal, StringFormat=N0}&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; VerticalAlignment=&amp;quot;Center&amp;quot; /&amp;gt;
                            &amp;lt;Label Content=&amp;quot;Cap Long&amp;quot; Width=&amp;quot;70&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; /&amp;gt;
                            &amp;lt;TextBlock x:Name=&amp;quot;longVal&amp;quot; Width=&amp;quot;60&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot; Text=&amp;quot;{Binding Path=LongCapVal, StringFormat=N0}&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; VerticalAlignment=&amp;quot;Center&amp;quot; /&amp;gt;
                            &amp;lt;Label Content=&amp;quot;Занято&amp;quot; Width=&amp;quot;60&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; Margin=&amp;quot;10,0,0,0&amp;quot; /&amp;gt;
                            &amp;lt;TextBlock x:Name=&amp;quot;filVal&amp;quot; Width=&amp;quot;40&amp;quot;  Text=&amp;quot;{Binding Path=longCount}&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; VerticalAlignment=&amp;quot;Center&amp;quot; /&amp;gt;
                            &amp;lt;Label Content=&amp;quot;Исп. капитала&amp;quot; Width=&amp;quot;100&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; /&amp;gt;
                            &amp;lt;TextBlock x:Name=&amp;quot;utilVal&amp;quot; Width=&amp;quot;60&amp;quot;  Text=&amp;quot;{Binding Path=longCapt, StringFormat=N0}&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; VerticalAlignment=&amp;quot;Center&amp;quot; /&amp;gt;
                            &amp;lt;Label Content=&amp;quot;Исп.%&amp;quot; Width=&amp;quot;50&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; /&amp;gt;
                            &amp;lt;TextBlock x:Name=&amp;quot;utilPcn&amp;quot; Width=&amp;quot;40&amp;quot; Text=&amp;quot;{Binding Path=longPcnt, StringFormat=P2}&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; VerticalAlignment=&amp;quot;Center&amp;quot; /&amp;gt;
                        &amp;lt;/DockPanel&amp;gt;
                        &amp;lt;robot:StrategyPlanDG x:Name=&amp;quot;myPlanDG&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot; Grid.Row=&amp;quot;2&amp;quot;/&amp;gt;
                    &amp;lt;/Grid&amp;gt;
                &amp;lt;/TabItem&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt; &lt;br /&gt;по умолчанию делаем элемент скрытым, чтобы не мешал при работе других стратегий.&lt;br /&gt;б) создаем StrategyBook для визуализации торговой книги&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:xml"&gt;

    &amp;lt;ListView x:Name=&amp;quot;BookView&amp;quot;  x:FieldModifier=&amp;quot;public&amp;quot; SelectionMode=&amp;quot;Single&amp;quot;
              DataContext=&amp;quot;{Binding RelativeSource={RelativeSource Self}}&amp;quot;
              HorizontalContentAlignment=&amp;quot;Stretch&amp;quot;&amp;gt;
        &amp;lt;ListView.View &amp;gt;
            &amp;lt;GridView &amp;gt;
                &amp;lt;GridViewColumn Width=&amp;quot;30&amp;quot;  Header=&amp;quot;Id&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=Id}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;Уровень&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=PlanPrice, StringFormat=F2}&amp;quot;/&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;100&amp;quot; Header=&amp;quot;Заявка покупки&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=BuyOrder}&amp;quot; /&amp;gt;
                &amp;lt;GridViewColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;Дата заявки&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=BuyOrderDate, StringFormat=&amp;#39;dd.MM.yy HH:mm&amp;#39;}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;100&amp;quot; Header=&amp;quot;Сделка покупки&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=BuyTrade, StringFormat=F0}&amp;quot; /&amp;gt;
                &amp;lt;GridViewColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;Дата покупки&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=BuyTradeDate,StringFormat=&amp;#39;dd.MM.yy HH:mm&amp;#39;}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;90&amp;quot; Header=&amp;quot;Цена покупки&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=BuyPrice, StringFormat=F2}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;50&amp;quot;  Header=&amp;quot;Объем&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=Amount}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;100&amp;quot; Header=&amp;quot;Заявка продажи&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=SellOrder}&amp;quot; /&amp;gt;
                &amp;lt;GridViewColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;Дата заявки&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=SellOrderDate, StringFormat=&amp;#39;dd.MM.yy HH:mm&amp;#39;}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;100&amp;quot; Header=&amp;quot;Сделка продажи&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=SellTrade, StringFormat=F0}&amp;quot; /&amp;gt;
                &amp;lt;GridViewColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;Дата продажи&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=SellTradeDate, StringFormat=&amp;#39;dd.MM.yy HH:mm&amp;#39;}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;90&amp;quot; Header=&amp;quot;Цена продажи&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=SellPrice, StringFormat=N2}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;80&amp;quot; Header=&amp;quot;Прибыль&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=prFit, StringFormat=F2}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;60&amp;quot; Header=&amp;quot;Приб.%&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=prPcn, StringFormat=P2}&amp;quot; /&amp;gt;
                    &amp;lt;GridViewColumn Width=&amp;quot;+60&amp;quot; Header=&amp;quot;Приб.год.&amp;quot; DisplayMemberBinding=&amp;quot;{Binding Path=prAnn, StringFormat=P2}&amp;quot; /&amp;gt;
            &amp;lt;/GridView&amp;gt;
            &amp;lt;/ListView.View&amp;gt;
        &amp;lt;/ListView&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;и так же выводим его в TestingPanel со начальным скрытым состоянием:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:xml"&gt;

                &amp;lt;TabItem x:Name=&amp;quot;TabBook&amp;quot; Header=&amp;quot;Book&amp;quot; Visibility=&amp;quot;Hidden&amp;quot;&amp;gt;
                    &amp;lt;robot:StrategyBook x:Name=&amp;quot;myMEQ&amp;quot; MinHeight=&amp;quot;200&amp;quot; Height=&amp;quot;Auto&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot;/&amp;gt;
                &amp;lt;/TabItem&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Как результат - получаем готовый интерфейс для управления работой стратегии в процессе ее выполнения.&lt;br /&gt;Это именно то, что никак невозможно сделать в  Tradematic в силу закрытости кода.</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/30323/</id>
    <title type="text">4) далее создаем торговую стратегию TLSStrategy, в которой основными свойствами будут --- private in...</title>
    <published>2014-04-14T14:49:41Z</published>
    <updated>2014-04-14T15:06:21Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">4) далее создаем торговую стратегию TLSStrategy, в которой основными свойствами будут&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

---
        private int _maxPrice = 110;
        [DisplayName(@&amp;quot;Max Price&amp;quot;)]
        [Description(@&amp;quot;Минимальная цена&amp;quot;)]
---
        private int _minPrice = 80;
        [DisplayName(@&amp;quot;Min Price&amp;quot;)]
        [Description(@&amp;quot;Максимальная цена&amp;quot;)]
---
        private int _step = 1;
        [DisplayName(@&amp;quot;Step&amp;quot;)]
        [Description(@&amp;quot;Шаг цены&amp;quot;)]
---
        private decimal _LongCapVal = 0;
        [Browsable(false)]
        [DisplayName(@&amp;quot;LongCapVal&amp;quot;)]
        [Description(@&amp;quot;Оценка капитала&amp;quot;)]
---
        private decimal _NBins = 0;
        [Browsable(false)]
        [DisplayName(@&amp;quot;NBins&amp;quot;)]
        [Description(@&amp;quot;Количество уровней&amp;quot;)]
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;В самой стратегии реализуем несколько открытых свойств для связи с интерфейсом: &lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        public int NBins { get; set; }
        public CandleSeries series { get; set; }
        public SynchronizedCollection&amp;lt;PlanElem&amp;gt; StrPlan { get; set; }
        public SynchronizedCollection&amp;lt;BookElem&amp;gt; StrBook { get; set; }
        public TradeManager trman;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;И далее создаем три основных процедуры, которые будут обеспечивать ее работу:&lt;br /&gt;а) процедуру инициации, основное предназначение которой - создать План торгов до старта стратегии&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

 public void Initialize()
        {
            this.Volume = Params.Volume;
            if (StrPlan == null || StrPlan.Count == 0) StrPlan = new SynchronizedCollection&amp;lt;PlanElem&amp;gt;();

            prmStr = new PlanParams();
            prmStr.MaxPriceVal = Params.Mode == enMode.Execution ? ((TLSStrProp)Params).MaxPrice : ((TLSTestProp)Params).MaxPrice;
            prmStr.CurPriceVal = Params.Mode == enMode.Execution ? ((TLSStrProp)Params).СurPrice : ((TLSTestProp)Params).СurPrice;
            prmStr.MinPriceVal = Params.Mode == enMode.Execution ? ((TLSStrProp)Params).MinPrice : ((TLSTestProp)Params).MinPrice;
            prmStr.StepVal = Params.Mode == enMode.Execution ? ((TLSStrProp)Params).Step : ((TLSTestProp)Params).Step;
            prmStr.CapShortVal = Params.Mode == enMode.Execution ? ((TLSStrProp)Params).CapShort : ((TLSTestProp)Params).CapShort;
            prmStr.CapLongVal = Params.Mode == enMode.Execution ? ((TLSStrProp)Params).CapLong : ((TLSTestProp)Params).CapLong;
            prmStr.MarginVal = Params.Mode == enMode.Execution ? Security.MarginBuy : ((BaseShellTestProp)Params).Margin;
            prmStr.Maxlength = 500;
            prmStr.iType = Security.ExchangeBoard == ExchangeBoard.Forts ? SecurityTypes.Future : SecurityTypes.Stock;

            trman = new TradeManager(this);
            trman.CreateTradePlan(prmStr);
            StrBook = trman.Book;
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;б) процедуру запуска,  в которой устанавливаем основные вызовы процедур обработки свечей и ведения Торговой книги&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        protected override void OnStarted()
        {
            base.OnStarted();
            if (StrPlan == null || StrPlan.Count == 0) Initialize();

            series
                .WhenCandlesFinished()
                .Do(ProcessCandle)
                .Apply(this);

            this.WhenOrderRegistered()
                .Do(trman.RegisterPosition) // Создание записи в журнале о заявке
                .Apply();

            this.WhenNewMyTrades()
                .Do(trman.UpdateBook) // Обновление позиции после выполнения заявки в торговой системе
                .Apply();
            
            this.OrdersKeepTime = TimeSpan.FromDays(30);
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;в) и конечно же процедуру обработки свечей, в которой реализуем основную логику создания заявок на покупку/продажу актива:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

private void ProcessCandle(Candle candle)
{
			
            var timeFrame = (TimeSpan)candle.Arg;
            var time = timeFrame.GetCandleBounds(Security).Min - timeFrame;
		    if (candle.OpenTime &amp;lt; time)
		        return;

		    _CandeslProcessed = _CandeslProcessed + 1;

            // если наша стратегия в процессе остановки
			if (ProcessState == ProcessStates.Stopping)
			{// отменяем активные заявки
				CancelActiveOrders();
				return;
			}

	   // обрабатываем новую свечку
            int mhit = 0;
	    decimal closepr = candle.ClosePrice;
            DateTime DT = candle.CloseTime;
            var planElemCur = new PlanElem();
            var planElemPrev = new PlanElem();

            for (int i = 1; i &amp;lt;= NBins; i++)
            {
                planElemCur = trman.Plan[i];
                planElemPrev = trman.Plan[i - 1];
                string s = &amp;quot;Hold&amp;quot;;
                if (closepr &amp;gt; planElemPrev.PlanPrice &amp;amp;&amp;amp; closepr &amp;lt;= planElemCur.PlanPrice)
                    mhit = i; // отмечаем уровень цены mhit как номер планового уровня i			

                if (mhit &amp;gt; 0 &amp;amp;&amp;amp; planElemCur.Vol == 0 &amp;amp;&amp;amp; planElemCur.TradeId == 0) // если цена ниже планового уровня, а уровень пуст то закупаем
                {   
                    var capAv = CheckCap();
                    if (capAv)
                    {//создаем ордер на открытие позиции
                        var order = this.CreateOrder(OrderDirections.Buy, closepr + 10 * Security.MinStepSize, Volume);
                        order.Comment = (i + 1).ToString(); // порядковый номер в плане i+1
                        planElemCur.Vol = (int)Volume;
                        planElemCur.BuyDate = DT;
                        RegisterOrder(order);
                        planElemCur.OrderId = order.TransactionId;
                    }
                    else
                    {  this.AddWarningLog(&amp;quot;Trade is missed for capital breach!&amp;quot;);
                    }                    
                }

                if (mhit == 0 &amp;amp;&amp;amp; planElemCur.Vol &amp;gt; 0 &amp;amp;&amp;amp; planElemPrev.TradeId &amp;gt; 0) // если на уровне ниже чем цена оказывается позиция j+1, то ее закрываем
                {
                    planElemPrev.SellDate = DT;
                    //создаем ордер на закрытие позиции                     
                    var orderCl = this.CreateOrder(OrderDirections.Sell, planElemPrev.SellPrice, planElemPrev.Vol);
                    orderCl.Comment = planElemPrev.OrderId.ToString(); // сохраняем первый номер для связки ордеров
                    RegisterOrder(orderCl);
                }
            }
    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;5) очевидно, что капитала может не хватить в процессе резкого падения рынка, как это было при присоединении Крыма, поэтому &lt;br /&gt;а) создаем свойства стратегии для хранения размера использованного капитала и %&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

         private decimal _longCapt = 0;
        [Browsable(false)]
        [DisplayName(@&amp;quot;longCapt&amp;quot;)]
        [Description(@&amp;quot;Использованный капитал&amp;quot;)]
---
        private decimal _longPcnt = 0;
        [Browsable(false)]
        [DisplayName(@&amp;quot;longPcnt&amp;quot;)]
        [Description(@&amp;quot;Процент использованния капитала&amp;quot;)]
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;б) создаем в классе TradeManager счетчик CalcCapReq для подсчета использованного капитала:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        public void CalcCapReq()
        {
            int longCountVal = 0;
            decimal longCaptVal = 0;
            decimal longPcntVal = 0;

            if (Plan == null) return;

            for (int i = 0; i &amp;lt;= _NBins; i++)
            {
                if (Plan[i].Vol &amp;gt; 0)
                {
                    longCountVal = longCountVal + 1;
                    longCaptVal = longCaptVal + Plan[i].CapLong;
                }
            }

            if (LongCapVal &amp;gt; 0)
                longPcntVal = longCaptVal / LongCapVal;
            else longPcntVal = 0;
      }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;в) вызываем данный счетчик после открытия длинной позиции, например в процедуре UpdateBook&lt;br /&gt;с) при обработки сигнала на покупки  проверяем наличие капитала в процедуре CheckCap&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        private bool CheckCap()
        {
            var lnCaP = (Params.Mode == enMode.Execution) ? ((TLSStrProp)Params).longPcnt : ((TLSTestProp)Params).longPcnt;
            if (lnCaP&amp;gt;(decimal)0.99) this.AddWarningLog(&amp;quot;Capital limit is reached&amp;quot;);
            return (lnCaP &amp;lt; 1);

        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;и если капитала недостаточно для удержания уже набранной позиции, то открытие новых позиций не проводим, создавая об этом запись в логе this.AddWarningLog(&amp;quot;Trade is missed for capital breach!&amp;quot;)</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/30322/</id>
    <title type="text">Часть 7 - Чем StockSharp круче Tradematic, или о миграции стратегий Итак рассмотрим вкратце миграцию...</title>
    <published>2014-04-14T14:34:01Z</published>
    <updated>2014-04-14T14:36:55Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">&lt;b&gt;Часть 7 - Чем StockSharp круче Tradematic, или о миграции стратегий&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Итак рассмотрим вкратце миграцию стратегий на примере простейшей стратегии торговли по линиям капитала, которая подробно изложена тут (http://robotcraft.ru/vstroeniestrategii/strateg-akc). Заодно пополним коллекцию торговых стратегий StockSharp достаточно надежной и низкорискованной стратегий, хотя с небольшой годовой доходностью (9% -15%).&lt;br /&gt;&lt;br /&gt;В целом система Tradematic так же позволяет программировать стратегии на с#, но без доступа к исходному коду оболочки, т.е. это что-то типа S#.Studio. &lt;br /&gt;При этом в ней есть ряд преимуществ по сравнению со S#.Studio:&lt;br /&gt;1) имеется встроенный оптимизатор стратегий,&lt;br /&gt;2) лицензия включает доступ к Серверу с историческими данными, позволяющему проводить облачное тестирование&lt;br /&gt;(как известно доступ к такому серверу StockSharp идет за отдельную плату),&lt;br /&gt;3) имеется &amp;quot;торговая книга&amp;quot;, которая автоматически матчит открытие и закрытие позиций.&lt;br /&gt;Но все эти преимущества меркнут по сравнению с теми колоссальными возможностями, которые нам дает открытая библиотека StockSharp, и которые будут проиллюстрированы ниже.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Итак для реализации нашей стратегии создаем общий класс TradeManager, назначением которого будет:&lt;br /&gt;1) создание и ведение Плана торговли(Plan),&lt;br /&gt;2) ведение Торговой книги(Book).&lt;br /&gt;Данный класс сразу делаем общий, так как он в дальнейшем может быть использован в пирамидальных стратегиях любой сложности.&lt;br /&gt;&lt;br /&gt;1) Создаем класс TradeManager и его инициализатор:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;
 
    public class TradeManager : ILogReceiver
    {
        private BaseShellStrategy _stratergy { get; set; }
        public Dictionary&amp;lt;int, PlanElem&amp;gt; Plan;
        public SynchronizedCollection&amp;lt;BookElem&amp;gt; Book;
        
        public TradeManager(BaseShellStrategy _str)
        {
            if (_stratergy==null) _stratergy = _str;
            if (Plan == null) Plan = new Dictionary&amp;lt;int, PlanElem&amp;gt;();
            if (Book == null) Book = new SynchronizedCollection&amp;lt;BookElem&amp;gt;();
        }        
     ...
    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;2) Для создания Плана торговли объявляем дополнительный класс PlanElem, каждый экземпляр которого будет содержать информацию об одной торговой линии:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

    public class PlanElem
    {
        public int Id { get; set; }
        public decimal PlanPrice { get; set; }
        public string SignalName { get; set; }
        public int Vol { get; set; }
        public decimal Amount { get; set; }
        public decimal SellPrice { get; set; }
        public decimal RiskShort { get; set; }
        public decimal RiskLong { get; set; }
        public DateTime BuyDate { get; set; }
        public DateTime SellDate { get; set; }
        public long OrderId { get; set; }
        public long TradeId { get; set; }
    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Так же создаем класс для быстрой параметризации Плана торговли при его первичном создании:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

    // Параметры плана торговли
    public class PlanParams
    {
        public int MaxPriceVal { get; set; }
        public int MinPriceVal { get; set; }
        public int StepVal { get; set; }
        public decimal riskShortVal { get; set; }
        public decimal riskLongVal { get; set; }
        public decimal MarginVal { get; set; }
    }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Далее создаем метод CreateTradePlan для создания План торговли по указанным параметрам:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

public void CreateTradePlan(PlanParams prm)
        {
            
            if (prm.MaxPriceVal &amp;lt;= prm.MinPriceVal || prm.MaxPriceVal == 0 || prm.MinPriceVal == 0 || prm.StepVal == 0 ||
                prm.StepVal &amp;gt;= prm.MinPriceVal)
                return;

            _NBins = 3 + (prm.MaxPriceVal - prm.MinPriceVal) / prm.StepVal;
            if (_NBins &amp;gt; prm.Maxlength)  // Ограничение на длину плана торгов
            {   
                this.AddErrorLog(&amp;quot;Вычисленная длина плана превышает допустимую&amp;quot;);
                return; 
            }

            decimal curLevel = 0;
            ShortCapVal = 0;
            LongCapVal = 0;

            for (int i = 0; i &amp;lt;= _NBins; i++)
            {
                
                planElem = new PlanElem();
                planElem.Id = i + 1;

                if (i == 0)
                {   planElem.PlanPrice = 0;
                    planElem.SellPrice = prm.MinPriceVal;
                }
                else if (i == 1)
                {   curLevel = prm.MinPriceVal;
                    planElem.SellPrice = curLevel + prm.StepVal;
                }
                else if (i == _NBins)
                {   curLevel = prm.MaxPriceVal;
                    planElem.SellPrice = prm.MaxPriceVal * 1000 + prm.StepVal;
                }
                else
                {   curLevel = curLevel + prm.StepVal;
                    planElem.SellPrice = curLevel + prm.StepVal;
                }

                planElem.PlanPrice = curLevel;
                planElem.Amount = _stratergy.Volume;
                if (prm.iType == SecurityTypes.Stock)
                {
                    planElem.CapShort = curLevel * _stratergy.Volume;
                    planElem.CapLong = curLevel * _stratergy.Volume;
                }
                else
                {
                    planElem.CapShort = (curLevel * prm.CapShortVal + prm.MarginVal) * _stratergy.Volume;
                    planElem.CapLong = (curLevel * prm.CapLongVal + prm.MarginVal) * _stratergy.Volume;
                }
                ShortCapVal = ShortCapVal + planElem.CapShort;
                LongCapVal = LongCapVal + planElem.CapLong;
                planElem.SignalName = &amp;quot;Buy at &amp;quot; + curLevel.ToString();
                planElem.Vol = 0;
                Plan.Add(i, planElem);
            }

            Book.Clear();
            this.AddInfoLog(&amp;quot;Создан План торговли из {0} уровней &amp;quot;.Put(_NBins));
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) Создаем процедуры для ведения Торговой книги:&lt;br /&gt;а) в первую очередь делаем процедуру первичной регистрации RegisterPosition, которая будет срабатывать сразу полсе появления заявки:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        public void RegisterPosition(Order ord)
        {
            if (ord.Direction == OrderDirections.Sell) return; // отсев заявок на продажу
            if (ord.Comment.Length &amp;gt; 3) return; // отсев заявок с перерегситрацией

            int curi = Book.Count();
            var inum = (int)ord.Comment.To&amp;lt;int&amp;gt;(); // порядковый номер плана
            var pl = Plan.TryGetValue(inum - 1);
            var BookElem = new BookElem();
            BookElem.Id = curi;
            BookElem.PlanPrice = pl.PlanPrice;
            BookElem.SignalId = pl.Id;
            BookElem.Amount = (int)_stratergy.Volume;
            BookElem.BuyOrder = ord.TransactionId;
            BookElem.BuyOrderDate = ord.LastChangeTime;
            Book.Add(BookElem);
            ord.Comment = &amp;quot;Уровень {0} зарегистрирован&amp;quot;.Put(inum);
            this.AddInfoLog(&amp;quot;Уровень {0} зарегистрирован&amp;quot;, ord.TransactionId);
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;б) затем создаем процедуру UpdateBook, которая призвана записывать в Торговую книгу данные о связанных сделках покупки и продажи:&lt;br /&gt;в зависимости от направления проводим связывание элементов Заявка-Сделка:&lt;br /&gt;- сделки на покупку сопоставляются с заявками по TransactionId, который предварительно сохраняется в поле BuyOrder при регистрации,&lt;br /&gt;- сделки на продажу сопоставляются со сделками на покупки по TransactionId, записанным в поле Comment заявки на продажу.&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        public void UpdateBook(IEnumerable&amp;lt;MyTrade&amp;gt; trades)
        {
            foreach (var myTrade in trades)
            {
                var ord = myTrade.Order;
                int ordnum = -1;

                if (ord.Direction == OrderDirections.Buy)
                { // дополняем таблицу данными о сделке покупки

                    string tID = ord.TransactionId.ToString();
                    if (tID.Length &amp;gt; 8)
                    { // вырезаем основную часть из заявок с переносом
                        tID = tID.Substring(0, 8);
                    }

                    var ordlast = Book.Where(f =&amp;gt; f.BuyOrder.ToString() == tID);
                    if (ordlast.Any() == false)
                    {
                        for (int i = 0; i &amp;lt; Book.Count; i++)
                            if (Book[i].f.BuyOrder.ToString() == tID) ordnum = i + 1;
                    }
                    else ordnum = ordlast.First().Id; // Key связанной Позиции

                    planElem = Plan[Book[ordnum].SignalId-1];
                    planElem.TradeId = myTrade.Trade.Id; // регистрируем выполнение заявки
                    
                    Book[ordnum].BuyPrice = myTrade.Trade.Price;
                    Book[ordnum].BuyTrade = myTrade.Trade.Id;
                    Book[ordnum].BuyTradeDate = myTrade.Trade.Time;

                }
                else
                { // дополняем таблицу данными о сделке продажи

                    var ordlast = Book.Where(f =&amp;gt; f.BuyOrder.ToString() == ord.Comment);
                    //ordlast = Book.Where(f =&amp;gt; String.Compare(f.BuyOrder.ToString(),ord.Comment)==0);
                    if (ordlast.Any() == false)
                    {
                        for (int i = 0; i &amp;lt; Book.Count; i++)
                            if (Book[i].ToString() == ord.Comment) ordnum = i + 1;
                    }
                    else ordnum = ordlast.First().Id;
                    
                    planElem = Plan[Book[ordnum].SignalId - 1];
                    planElem.TradeId = 0; // регистрируем выполнение заявки
                    planElem.Vol = 0; // снимаем размер 

                    Book[ordnum].SellOrder = ord.TransactionId;
                    Book[ordnum].SellOrderDate = ord.Time;
                    Book[ordnum].SellPrice = myTrade.Trade.Price;
                    Book[ordnum].SellTrade = myTrade.Trade.Id;
                    Book[ordnum].SellTradeDate = myTrade.Trade.Time;
                    Book[ordnum].prFit = Book[ordnum].SellPrice - Book[ordnum].BuyPrice;
                    Book[ordnum].prPcn = Book[ordnum].prFit / Book[ordnum].BuyPrice;

                    var span = (Book[ordnum].SellTradeDate - Book[ordnum].BuyTradeDate);
                    decimal spanVal = 0; 
                    if   (span.TotalDays &amp;lt; 1) spanVal = 1;
                    else spanVal = (decimal) span.TotalDays;
                    Book[ordnum].prAnn = Book[ordnum].prPcn * 365 / spanVal;

                 }

            }
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/29945/</id>
    <title type="text">methyst, тут такие правила что по окончанию срока обучения (1,5 или 3 мес ) пользователей отключают ...</title>
    <published>2014-03-10T16:38:04Z</published>
    <updated>2014-03-10T16:38:04Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">methyst, тут такие правила что по окончанию срока обучения (1,5 или 3 мес ) пользователей отключают от TFS.&lt;br /&gt;По вопросу - полагаю что смысла каждому пользователю выкладывать свои программы на TFS особого нет. &lt;br /&gt;Материалы я тут опубликовал для общего развития тех кто захочет сам допиливать Shell.</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/29941/</id>
    <title type="text">lebedevsrg, собираетесь ли Вы выкладывать свою версию shell&amp;apos;a куда-нибудь?</title>
    <published>2014-03-10T07:55:46Z</published>
    <updated>2014-03-10T07:55:46Z</updated>
    <author>
      <name>methyst</name>
      <uri>https://stocksharp.ru/users/51028/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">lebedevsrg, собираетесь ли Вы выкладывать свою версию shell&amp;#39;a куда-нибудь?</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/29871/</id>
    <title type="text">Часть 6 - Тотальный апгрейд Итак имеем S#.Shell на основе S#.API 4.1.15.0 и решаемся на апгрейд до в...</title>
    <published>2014-03-01T13:14:54Z</published>
    <updated>2014-03-01T13:17:35Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">&lt;b&gt;Часть 6 - Тотальный апгрейд&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Итак имеем S#.Shell на основе S#.API 4.1.15.0 и решаемся на апгрейд до версии 4.2.2.16.&lt;br /&gt;Сразу же получаем множество заменой iTrader на Connector, и еще с десяток проблемных мелочей типа замены свойств, которые решаются в течение получаса&lt;br /&gt;&lt;br /&gt;Но так же вылезают две более серьезные проблемы, о которых имеет смысл тут рассказать.&lt;br /&gt;&lt;br /&gt;1. В XAML отваливается весь CommandBinding с тупым сообщением &amp;quot;Член не распознан&amp;quot;))&lt;br /&gt;Как единственное найденное 100% работающее решение данной проблемы - перенос всего CommandBindingа из XAML в программный код.&lt;br /&gt;Для этого делаем три простых шага:&lt;br /&gt;1) в MainWindow.xaml полностью удаляем содержание раздела &amp;lt;Window.CommandBindings&amp;gt; и привязки команд типа Command=&amp;quot;{x:Static Robot:MainWindow.ConnectCommand}&amp;quot;, а вместо этого для каждого элемента, которому необходимо привязать RoutedCommand задаем имя через тег x:Name&lt;br /&gt;2) в MainWindow.xaml.cs создаем новую процедуру  private void InitializeCommands(), в которой для каждого управляющего элемента создаем связь через класс CommandBinding (на примере пункта меню &amp;quot;Подключиться&amp;quot;):&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            CommandBinding ccBinding1 = new CommandBinding(ConnectCommand, ExecutedConnect, CanExecuteConnect);
            this.CommandBindings.Add(ccBinding1);
            miConnect.Command = ConnectCommand;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;где ConnectCommand - исходная RoutedCommand,&lt;br /&gt;    ExecutedConnect - основная процедура для выполнения,&lt;br /&gt;    CanExecuteConnect - связанная проверочная процедура возможности выполнения основной процедуры,&lt;br /&gt;    miConnect - название элемента пункта меню &amp;quot;Подключиться&amp;quot;,&lt;br /&gt;далее в тоже процедуре InitializeCommands() создаем необходимые элементы для быстрых клавиш:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            KeyGesture OpenKeyGesture1 = new KeyGesture(Key.P,ModifierKeys.Control);
            InputBinding KeyBinding1 = new KeyBinding(SettingsCommand, OpenKeyGesture1);
            this.InputBindings.Add(KeyBinding1);
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;3) вызываем InitializeCommands() в теле процедуры MainWindow().&lt;br /&gt;&lt;br /&gt;2. В S#.API версии 4.2.2.16 обнаруживаем, что в режиме эмуляции ни один из коннекторов (проверено на AlfaTrader/TransaqTrader) не получает портфели. Соответственно тестирование в эмуляции невозможно.&lt;br /&gt;Для решения этой проблемы делаем два шага:&lt;br /&gt;1) создаем в классе ConnectionEngine свойство IsEmulation:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

                   public bool IsEmulation { get { return settings.Emulation; } }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;2)добавляем в код процедуры StartStrategy специальную проверку на режим эмуляции и в случае оного, создаем тестовый портфель, который и привязываем к коннектору:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;
 
		    var portfolio = ConnectionEngine.Instance.Trader.Portfolios.FirstOrDefault(p =&amp;gt; p.Name == strategy.Params.Portfolio);
		    if (portfolio == null)
		    {
		        if (ConnectionEngine.Instance.IsEmulation)
		        {
                    var portf = new Portfolio{Name = &amp;quot;TestAcc&amp;quot;,BeginValue = 1000000,CurrentValue = 1000000};
                    ConnectionEngine.Instance.Trader.RegisterPortfolio(portf);
                    ConnectionEngine.Instance.Trader.TransactionAdapter.SendInMessage(portf.ToMessage());
                    var pcm =new PortfolioChangeMessage{PortfolioName = portf.Name}.Add(PositionChangeTypes.BeginValue, portf.BeginValue);
		            ConnectionEngine.Instance.Trader.TransactionAdapter.SendInMessage(pcm);
                    var pcm2 = new PortfolioChangeMessage { PortfolioName = portf.Name }.Add(PositionChangeTypes.CurrentValue, portf.CurrentValue);
                    ConnectionEngine.Instance.Trader.TransactionAdapter.SendInMessage(pcm2);
		            strategy.Portfolio = portf;
                    strategy.AddWarningLog(&amp;quot;Создан портфель {0} для запуска стратегии&amp;quot;, portf.Name);
		        }
		        else
		        {
                    strategy.AddErrorLog(&amp;quot;Не найден портфель {0} для запуска стратегии&amp;quot;, strategy.Params.Portfolio);
                    return;    
		        }
		        
		    }
		    else
		        strategy.Portfolio = portfolio;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;         &lt;br /&gt;    &lt;br /&gt;Вуаля- все работает как нужно!</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/29781/</id>
    <title type="text">на мой взгляд использование дочерних стратегий тут дело вкуса - кому-то идет, а кому-то нет; в силу ...</title>
    <published>2014-02-24T17:45:20Z</published>
    <updated>2014-02-24T17:45:20Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">на мой взгляд использование дочерних стратегий тут дело вкуса - кому-то идет, а кому-то нет; в силу разных обстоятельств - и дебаггить их невозможно, условия срабатывания ограничены (н--р нет стоп-лосса исходя из % годовых) и пр.</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/29710/</id>
    <title type="text">А почему для установки стопов не пользуетесь StopLossStrategy, а в ручную их отслеживаете?</title>
    <published>2014-02-20T17:33:57Z</published>
    <updated>2014-02-20T17:33:57Z</updated>
    <author>
      <name>kesot</name>
      <uri>https://stocksharp.ru/users/50459/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">А почему для установки стопов не пользуетесь StopLossStrategy, а в ручную их отслеживаете?</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/29606/</id>
    <title type="text">Часть 5. Чему нас учит семья и школа Интерфейс тестирования S#.Shell по умолчанию не достаточен для ...</title>
    <published>2014-02-16T15:39:36Z</published>
    <updated>2014-02-16T15:44:22Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">&lt;b&gt;Часть 5. Чему нас учит семья и школа&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Интерфейс тестирования S#.Shell по умолчанию не достаточен для эффективного тестирования стратегии при ее первичном кодировании, так как в этом тонком процессе переноса собственного нейронного вещества в машинный код возникает множество нюансов а-ля &amp;quot;сделка не выполнилась в силу неизвестных причин&amp;quot;, в которых невозможно разобраться без  соответствующих инструментов.&lt;br /&gt;&lt;br /&gt;Поэтому добавляем в наш S.Shell основные инструменты визуализации процесса исполнения стратегии, которые нам уже знакомы по курсу S#.Education - исторический график свечей, таблицу заявок и таблицу собственных сделок.&lt;br /&gt;&lt;br /&gt;5.1. Создаем на TestingPanel элемент типа TabControl, в который добавляем вкладки для каждого инструмента: &lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:java"&gt;

                &amp;lt;TabItem x:Name=&amp;quot;TabHist&amp;quot; Header=&amp;quot;History&amp;quot;&amp;gt;
                    &amp;lt;chart:Chart x:Name=&amp;quot;HistoryChart&amp;quot; MinHeight=&amp;quot;200&amp;quot; Height=&amp;quot;Auto&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot;/&amp;gt;
                &amp;lt;/TabItem&amp;gt;
                &amp;lt;TabItem x:Name=&amp;quot;TabPNL&amp;quot; Header=&amp;quot;PNL&amp;quot;&amp;gt;
                    &amp;lt;chart:EquityCurveChart x:Name=&amp;quot;CurveChart&amp;quot; MinHeight=&amp;quot;200&amp;quot; Height=&amp;quot;Auto&amp;quot;  x:FieldModifier=&amp;quot;public&amp;quot;/&amp;gt;
                &amp;lt;/TabItem&amp;gt;
                &amp;lt;TabItem x:Name=&amp;quot;TabORD&amp;quot; Header=&amp;quot;Orders&amp;quot;&amp;gt;
                    &amp;lt;xaml:OrderGrid x:Name=&amp;quot;myOrders&amp;quot; MinHeight=&amp;quot;200&amp;quot; Height=&amp;quot;Auto&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot;/&amp;gt;
                &amp;lt;/TabItem&amp;gt;
                &amp;lt;TabItem x:Name=&amp;quot;TabTRD&amp;quot; Header=&amp;quot;Trades&amp;quot;&amp;gt;
                    &amp;lt;xaml:MyTradeGrid x:Name=&amp;quot;myTrades&amp;quot; MinHeight=&amp;quot;200&amp;quot; Height=&amp;quot;Auto&amp;quot; x:FieldModifier=&amp;quot;public&amp;quot;/&amp;gt;
                &amp;lt;/TabItem&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;5.2. В общем-то мы понимаем, что графические элементы в целом тормозят тестирование и нужны будут не всегда, а в основном при кодинге новых стратегий, поэтому в свойства базовой стратегии тестирования BaseShellStrategy добваляем свойства для управления отображением их в ходе тестирования:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

        private bool _chartPL = false;
        [Category(@&amp;quot;Отрисовка&amp;quot;)]
        [DisplayName(@&amp;quot;График P&amp;amp;L&amp;quot;)]
        [Description(@&amp;quot;Вывод графика P&amp;amp;L при тестировании&amp;quot;)]
        [PropertyOrder(0)]
        public bool chartPL
        {
            get { return _chartPL; }
            set
            {
                _chartPL = value;
                OnPropertyChanged(&amp;quot;chartPL&amp;quot;);
            }
        }

        private bool _chartHC = false;
        [Category(@&amp;quot;Отрисовка&amp;quot;)]
        [DisplayName(@&amp;quot;График свечей&amp;quot;)]
        [Description(@&amp;quot;Вывод графика свечей  при тестировании&amp;quot;)]
        [PropertyOrder(2)]
        public bool chartHC
        {
            get { return _chartHC; }
            set
            {
                _chartHC = value;
                OnPropertyChanged(&amp;quot;chartHC&amp;quot;);
            }
        }

        private bool _chartTrd = false;
        [Category(@&amp;quot;Отрисовка&amp;quot;)]
        [DisplayName(@&amp;quot;Сделки&amp;quot;)]
        [Description(@&amp;quot;Вывод всех сделок на график истории&amp;quot;)]
        [PropertyOrder(2)]
        public bool chartTrd
        {
            get { return _chartTrd; }
            set
            {
                _chartTrd = value;
                OnPropertyChanged(&amp;quot;chartTrd&amp;quot;);
            }
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5.3. В процедуре тестирования стратегии StartTesingStrategy прописываем код для обоработки каждого нового инструмента:&lt;br /&gt;а) для истории свечей:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            if (parameters.chartHC)
            {
                    histChart = doc.TestingPanel.HistoryChart;
                    histChart.Areas.Clear();
                    histChart.IsAutoScroll = true;
                    _area = new ChartArea(); //создаем область на графике
                    histChart.Areas.Add(_area); //добавляем область на график
                    _candlesElem = new ChartCandleElement(); //создаем элемент свечи
                    _area.Elements.Add(_candlesElem); //добавляем элемент в область вывода графика
                    _candleManager.Processing += (series, cnd) =&amp;gt;
                    {
                        if (cnd.State == CandleStates.Finished)
                        {
                            var myDic = new Dictionary&amp;lt;IChartElement, object&amp;gt;();
                            myDic.Add(_candlesElem, cnd);
                            MainWindow.Instance.GuiAsync(() =&amp;gt; histChart.ProcessValues(cnd.OpenTime, myDic));
                        }
                    };
            }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;б) для отражения истории сделок:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            if (parameters.chartHC &amp;amp;&amp;amp; parameters.chartTrd)
            {
                    var _tradeElement = new ChartTradeElement();
                    _area.Elements.Add(_tradeElement);
                    _strategy.NewMyTrades += (trds) =&amp;gt; 
                        trds.ForEach(t =&amp;gt;
                        {
                            var tradeTime = _timeFrame.GetCandleBounds(t.Trade.Time).Min;
                            var myDic = new Dictionary&amp;lt;IChartElement, object&amp;gt;() { { _tradeElement, t } };
                            MainWindow.Instance.GuiAsync(() =&amp;gt; histChart.ProcessValues(tradeTime, myDic));
                        });
            }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;в) для таблицы заявок:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            var _myOrders = doc.TestingPanel.myOrders;
            _myOrders.Orders.Clear();
            _strategy.OrderRegistered += (ord) =&amp;gt; MainWindow.Instance.GuiAsync(() =&amp;gt; _myOrders.Orders.Add(ord));
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;г) для таблицы сделок:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            var _myTrades = doc.TestingPanel.myTrades;
            _myTrades.Trades.Clear();
            _strategy.NewMyTrades += (trd) =&amp;gt; trd.ForEach(t =&amp;gt; MainWindow.Instance.GuiAsync(() =&amp;gt; _myTrades.Trades.Add(t)));
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;И в результате все работет отлично, кроме корректного отображения сделок))</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/29548/</id>
    <title type="text">Часть 4. Универсализация создания, тестирования и исполнения стратегий Первое что мне бросилось в гл...</title>
    <published>2014-02-12T12:50:02Z</published>
    <updated>2014-02-16T15:17:00Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">&lt;b&gt;Часть 4. Универсализация создания, тестирования и исполнения стратегий&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Первое что мне бросилось в глаза в версии от Kazai Mazai, которую я продолжил допиливать - отсутствие универсальности в исполнении/тестировании одной и той же стратегии.&lt;br /&gt;Так если запустить стратегию RobotStrategy на тестирование, то следующий участок кода стратегии: &lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

... lock (this)
	{
	  if (_bidOrder == null &amp;amp;&amp;amp; _askOrder == null)
		{
		// проверяем на сигнал на вход
	       var spread = (ask - bid) / Security.MinStepSize;

		if (spread &amp;gt;= ((RobotStrategyProperties)Params).Spread)
...
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;вызовет ошибку &amp;quot;Не удалось привести тип объекта &amp;quot;System.Collections.Generic.List`1[Robot.Strategies.HustleEveryDayStrategyTestingProperties]&amp;quot; к типу &amp;quot;System.Collections.Generic.List`1[Robot.Strategies.HustleEveryDayStrategyProperties]&amp;quot;.&lt;br /&gt;&lt;br /&gt;Для решения этой проблемы введем в класс BaseShellStrategyProperties два параметра &amp;quot;Класс стратегии&amp;quot; и &amp;quot;Режим запуска&amp;quot;:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;


        public enum enMode
        {
           Execution,
           Testing
        }

        private string _classname = &amp;quot;Класс стратегии&amp;quot;;
        [DisplayName(@&amp;quot;Класс&amp;quot;)]
        [Description(@&amp;quot;Класс стратегии&amp;quot;)]
        [Category(@&amp;quot;Основные&amp;quot;)]
        [PropertyOrder(1)]
        public string ClassName
        {
            get { return _classname; }
            set
            {
                _classname = value;
                OnPropertyChanged(&amp;quot;ClassName&amp;quot;);
            }
        }


        private enMode _mode = enMode.Testing;
        [Category(@&amp;quot;Основные&amp;quot;)]
        [DisplayName(@&amp;quot;Режим запуска&amp;quot;)]
        [Description(@&amp;quot;Режим запуска стратегии&amp;quot;)]
        [PropertyOrder(2)]
        public enMode Mode
        {
            get { return _mode; }
            set
            {
                _mode = value;
                OnPropertyChanged(&amp;quot;Mode&amp;quot;);
            }
        }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Данные свойства необходимо определять во всех процедурах типа AddХХХХStrategy.&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

     private void AddRobotStrategy()
        {
            var properties = new RobotStrategyProperties
            {
                ClassName = &amp;quot;Robot&amp;quot;,
                Mode = enMode.Execution
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4.1. Универсализация исполнения стратегий&lt;br /&gt;Все параметры внутри стратегии обертываем процедурой if, которая проверяет режим запуска и проводит правильное приведение типов данных:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            int StopVal = 1;
            if (Params.Mode == enMode.Execution)
                StopVal = ((RobotStrategyProperties)Params).Stop;
            else
                StopVal = ((RobotTestingProperties)Params).Stop;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4.2. Универсализация тестирования стратегий&lt;br /&gt;В основную процедуру запуска стратегий на тестирование StartTesingStrategy добавляем проверка класса стратегии при задании специфичных параметров:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

            if (parameters.ClassName == &amp;quot;Sma&amp;quot; || parameters.ClassName == &amp;quot;TLS&amp;quot;)
            {
                switch (parameters.ClassName)
                {
                    case  &amp;quot;Sma&amp;quot;:
                        ((SmaStrategy)_strategy).series = _series;
                        break;
                    case &amp;quot;TLS&amp;quot;:
                        ((TLSStrategy)_strategy).series = _series;
                        break;
                }
            }
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4.3. Универсализация сохранения настроек стратегий&lt;br /&gt;В основной процедуре сохранения настроек стратегии SaveStrategies проводим модификацию запроса Where&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

var robotstrategies = _documents.Keys.Where(str =&amp;gt; str.Params.ClassName == &amp;quot;Robot&amp;quot; &amp;amp;&amp;amp; str.Params.Mode == enMode.Execution).Select(str =&amp;gt; (RobotStrategyProperties)str.Params).ToList();
SettingsEngine.Instance.SaveRobotStrategies(robotstrategies);

var hustlestrategies = _documents.Keys.Where(str =&amp;gt; str.Params.ClassName == &amp;quot;Hustle&amp;quot; &amp;amp;&amp;amp; str.Params.Mode == enMode.Execution).Select(str =&amp;gt; (HustleStrategyProperties)str.Params).ToList();
SettingsEngine.Instance.SaveHustleStrProp(hustlestrategies);
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4.4. Устранение бага отображения стратегий на панели &amp;quot;Стратегии&amp;quot;&lt;br /&gt;В поставляемой версии на панели &amp;quot;Стратегии&amp;quot; не отражаются тестовые стратегии. Для устранения этого бага проводим универсализацию хранения стратегий в переменной _documents.&lt;br /&gt;а) везде в процедурах создания стратегий проводим сохранение стратегий в переменную _documents:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

                _documents.Add(strategy, doc); 
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;б) в свойстве SelectedStrategy дописываем условие выбора документа типа TestingDocument:&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

                var doc = dockManager.ActiveContent;

                if (doc is StrategyDocument)
                {
                    var content = (StrategyDocument)doc;
                    result = content.Strategy;
                }
                else
                {
                    var content = (TestingDocument)doc;
                    result = content.Strategy;
                }
                return result;
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;Теперь все отображается корректно.&lt;br /&gt;в) дополнительно можно вообще удалить процедуру SaveTestingStrategies, поместив соответствующие обработки в SaveStrategies: &lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

var robotTstrategies = _documents.Keys.Where(str =&amp;gt; str.Params.ClassName == &amp;quot;Robot&amp;quot; &amp;amp;&amp;amp; str.Params.Mode == enMode.Testing).Select(str =&amp;gt; (RobotStrategyTestingProperties)str.Params).ToList();
SettingsEngine.Instance.SaveRobotTestingStrategies(robotTstrategies);

var hustleTstrategies = _documents.Keys.Where(str =&amp;gt; str.Params.ClassName == &amp;quot;Hustle&amp;quot; &amp;amp;&amp;amp; str.Params.Mode == enMode.Testing).Select(str =&amp;gt; (HustleStrategyTestingProperties)str.Params).ToList();
SettingsEngine.Instance.SaveHustleTestStrProp(hustleTstrategies);
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&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.ru/posts/m/29547/</id>
    <title type="text">Месяц прошел - и молчание разработчиков!)) На самом деле Shell действительно достаточно сырой продук...</title>
    <published>2014-02-12T12:10:10Z</published>
    <updated>2014-02-12T12:10:10Z</updated>
    <author>
      <name>JaguarFX</name>
      <uri>https://stocksharp.ru/users/49779/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">Месяц прошел - и молчание разработчиков!))&lt;br /&gt;На самом деле Shell действительно достаточно сырой продукт, в который необходимо много вложить чтобы получить выхлоп.&lt;br /&gt;Даже в версии от  Казакова Сергея достаточно ошибок и неточностей, на исправление которых у меня ушло множество времени.&lt;br /&gt;&lt;br /&gt;Так почти месяц назад я поставил для себя цель провести миграцию своих торговых роботов с платформы TradeMatic на платформу S#.Shell, и за это время наработал материал, которым стоит поделиться дабы не возникали подобные вопросы.&lt;br /&gt;</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/29134/</id>
    <title type="text">скачал версию 4.2.2, там вообще Shell не открывается, библиотек основных нет. </title>
    <published>2014-01-18T19:38:44Z</published>
    <updated>2014-01-18T19:38:44Z</updated>
    <author>
      <name>dij1</name>
      <uri>https://stocksharp.ru/users/339/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">скачал версию 4.2.2, там вообще Shell не открывается, библиотек основных нет. </content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/29081/</id>
    <title type="text">где взять исходники S#.Shell, тем у кого лицензия это позволяет? Дайте, пожалуйста, ссылку.</title>
    <published>2014-01-15T18:48:33Z</published>
    <updated>2014-01-15T18:49:12Z</updated>
    <author>
      <name>Aton5</name>
      <uri>https://stocksharp.ru/users/28158/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">где взять исходники  S#.Shell, тем у кого лицензия это позволяет?&lt;br /&gt;Дайте, пожалуйста, ссылку.</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/28647/</id>
    <title type="text">Интересно, это только у меня в каркасе в таблице сделки, отображается только первая сделка? Никакие ...</title>
    <published>2013-12-12T20:17:59Z</published>
    <updated>2013-12-12T20:17:59Z</updated>
    <author>
      <name>Kazai Mazai</name>
      <uri>https://stocksharp.ru/users/5954/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">&lt;div class="quote"&gt;&lt;span class="quotetitle"&gt;liftrade &lt;a href="https://stocksharp.ru/posts/m/28589/" class="quote_nav"&gt;&lt;/a&gt;&lt;/span&gt;&lt;div class="innerquote"&gt;Интересно, это только у меня в каркасе в таблице сделки, отображается только первая сделка? Никакие последующие в нее не заносятся... Или это общий баг такой?&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;да у меня тоже был такой баг, почему-то insert не так работает, как хотелось бы.&lt;br /&gt;&lt;br /&gt;В StrategyDocument.xaml.cs меняем  закомментированное на незакомментированное.&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;

_strategy.NewMyTrades += trades =&amp;gt;
				{
					foreach (var trade in trades)
					{
                                                _tradeGrid.Trades.Add(trade.Trade);
						//_tradeGrid.Trades.Insert(0, trade.Trade);
					}
				};
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&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.ru/posts/m/28589/</id>
    <title type="text">Интересно, это только у меня в каркасе в таблице сделки, отображается только первая сделка? Никакие ...</title>
    <published>2013-12-03T10:21:06Z</published>
    <updated>2013-12-05T08:25:54Z</updated>
    <author>
      <name>liftrade</name>
      <uri>https://stocksharp.ru/users/26843/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">Интересно, это только у меня в каркасе в таблице сделки, отображается только первая сделка? Никакие последующие в нее не заносятся... Или это общий баг такой?</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.ru/posts/m/28292/</id>
    <title type="text">По просьбам телезрителей(как минимум одного) сделал зарисовочку для сопровождения позиции. Открывает...</title>
    <published>2013-11-18T20:28:18Z</published>
    <updated>2013-11-18T20:33:46Z</updated>
    <author>
      <name>Kazai Mazai</name>
      <uri>https://stocksharp.ru/users/5954/</uri>
      <email>info@stocksharp.ru</email>
    </author>
    <content type="html">По просьбам телезрителей(как минимум одного) сделал зарисовочку для сопровождения позиции.&lt;br /&gt;Открывается прямо при старте, и выходит в какое-то время, а также по стопам и нескольким ценовым тейкам, передвигая стоп в б\у.&lt;br /&gt;Есть кое-какие лишние проверки, потому что кусочки взяты из стратегии на нескольких инструментах, но хуже не будет.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;strong&gt;Код&lt;/strong&gt;&lt;div class="innercode"&gt;&lt;pre class="brush:csharp"&gt;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Ecng.Common;
using StockSharp.Algo;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Logging;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;

namespace Robot.Strategies
{
    public class HustleEveryDayStrategyProperties :BaseShellStrategyProperties
    {

        private decimal _takeProfit1 = 10000000;
        [DisplayName(@&amp;quot;1-й тейк профит&amp;quot;)]
        [Description(@&amp;quot;Цена для 1-й цели&amp;quot;)]
        [Category(@&amp;quot;Параметры&amp;quot;)]
        [PropertyOrder(0)]
        public decimal TakeProfit1
        {
            get { return _takeProfit1; }
            set
            {
                _takeProfit1 = value;
                OnPropertyChanged(&amp;quot;TakeProfit1&amp;quot;);
            }
        }



        private decimal _takeProfit2 = 10000000;
        [DisplayName(@&amp;quot;2-й тейк профит&amp;quot;)]
        [Description(@&amp;quot;Цена для 2-й цели&amp;quot;)]
        [Category(@&amp;quot;Параметры&amp;quot;)]
        [PropertyOrder(0)]
        public decimal TakeProfit2
        {
            get { return _takeProfit2; }
            set
            {
                _takeProfit2 = value;
                OnPropertyChanged(&amp;quot;TakeProfit2&amp;quot;);
            }
        }
        private decimal _takeProfit3 = 10000000;
        [DisplayName(@&amp;quot;3-й тейк профит&amp;quot;)]
        [Description(@&amp;quot;Цена для 3-й цели&amp;quot;)]
        [Category(@&amp;quot;Параметры&amp;quot;)]
        [PropertyOrder(0)]
        public decimal TakeProfit3
        {
            get { return _takeProfit3; }
            set
            {
                _takeProfit3 = value;
                OnPropertyChanged(&amp;quot;TakeProfit3&amp;quot;);
            }
        }

        private decimal _stoploss = 10000000;
        [DisplayName(@&amp;quot;стоп лосс&amp;quot;)]
        [Description(@&amp;quot;Цена для стоп лосса&amp;quot;)]
        [Category(@&amp;quot;Параметры&amp;quot;)]
        [PropertyOrder(0)]
        public decimal Stoploss
        {
            get { return _stoploss; }
            set
            {
                _stoploss = value;
                OnPropertyChanged(&amp;quot;Stoploss&amp;quot;);
            }
        }
        private DateTime _closeTime = new DateTime(2000,1,1,1,1,1);
        [DisplayName(@&amp;quot;Время закрытия&amp;quot;)]
        [Description(@&amp;quot;Время закрытия сделки&amp;quot;)]
        [Category(@&amp;quot;Параметры&amp;quot;)]
        [PropertyOrder(0)]
        public DateTime CloseTime
        {
            get { return _closeTime; }
            set
            {
                _closeTime = value;
                OnPropertyChanged(&amp;quot;CloseTime&amp;quot;);
            }
        }

        private OrderDirections _orderDirection = OrderDirections.Buy;
        [DisplayName(@&amp;quot;Направление сделки&amp;quot;)]
        [Description(@&amp;quot;Направление сделки&amp;quot;)]
        [Category(@&amp;quot;Параметры&amp;quot;)]
        [PropertyOrder(0)]
        public OrderDirections OrderDirection
        {
            get { return _orderDirection; }
            set
            {
                _orderDirection = value;
                OnPropertyChanged(&amp;quot;OrderDirection&amp;quot;);
            }
        }


    }

    public class  HustleEveryDayStrategyTestingProperties:BaseShellTestingProperties
    {
        

    }


   public class HustleEveryDayStrategy:BaseShellStrategy
    {
       protected override void OnStarted()
       {

           base.OnStarted();

           var currentTime = Trader.GetMarketTime(Security.ExchangeBoard.Exchange);
           this.AddInfoLog(&amp;quot;Текущее рыночное время: {0}.&amp;quot;.Put(currentTime));

           var currentClosePositionsTime = ((HustleEveryDayStrategyProperties) Params).CloseTime;
           this.AddInfoLog(&amp;quot;Текущее время проверки выхода по тайм-стопу: {0}.&amp;quot;.Put(currentClosePositionsTime));
           if (currentTime &amp;gt; currentClosePositionsTime)
           {
               var newClosePositionsTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day,
                                                        currentClosePositionsTime.Hour, currentClosePositionsTime.Minute,
                                                        currentClosePositionsTime.Second);
               this.AddInfoLog(&amp;quot;Новое время проверки выхода по тайм-стопу: {0}.&amp;quot;.Put(newClosePositionsTime));
               ((HustleEveryDayStrategyProperties) Params).CloseTime = newClosePositionsTime;
           }

           
           Security
             .WhenTimeCome(((HustleEveryDayStrategyProperties)Params).CloseTime)
             .Do(CheckForExitByTimeTargets)
             .Apply(this);

           Security
                   .WhenChanged()
                   .Do(CheckForExitByPriceTargets)
                   .Apply(this);

           SubscriptionEngine.Instance.RegisterSecurity(this, Security);

           if(((HustleEveryDayStrategyProperties)Params).OrderDirection==OrderDirections.Buy)
           {
               PlaceBuyMarketOrder(Security,Volume);

           }
           else
           {
               PlaceSellMarketOrder(Security, Volume);
           }

       }

       private  void CheckForExitByPriceTargets()
       {

         this.AddInfoLog(&amp;quot;Проверка выхода по целям.&amp;quot;);
       
         if( PositionManager.Positions.Any(p=&amp;gt; p.Security.Code==Security.Code))
         {
             var position = PositionManager.Positions.First(p =&amp;gt; p.Security.Code == Security.Code);
             if (position.CurrentValue &amp;gt; 0)
             {
                 if (Security.LastTrade.Price &amp;lt;= ((HustleEveryDayStrategyProperties)Params).Stoploss)
                 { 
                    PlaceSellMarketOrder(position.Security, position.CurrentValue);
                    return;
                 }

                 if (Security.LastTrade.Price &amp;gt;= ((HustleEveryDayStrategyProperties)Params).TakeProfit3)
                 {
                     PlaceSellMarketOrder(position.Security, position.CurrentValue);
                     return;
                 }

                 if (Security.LastTrade.Price &amp;gt;= ((HustleEveryDayStrategyProperties)Params).TakeProfit2)
                 {
                     PlaceSellMarketOrder(position.Security,decimal.Floor(0.5m*position.CurrentValue));
                     ((HustleEveryDayStrategyProperties)Params).Stoploss =
                         ((HustleEveryDayStrategyProperties)Params).TakeProfit1;

                     return;
                 }
                 if (Security.LastTrade.Price &amp;gt;= ((HustleEveryDayStrategyProperties)Params).TakeProfit1)
                 {
                   
                     PlaceSellMarketOrder(position.Security, decimal.Floor(0.33m * position.CurrentValue));
                   
                     if(MyTrades.Any(t=&amp;gt;t.Trade.Security.Code==Security.Code))
                     {
                        var myTradesOrderedByDate = MyTrades.ToList().OrderBy(t =&amp;gt; t.Trade.Time);
                        var trade = myTradesOrderedByDate.Last(t =&amp;gt; t.Trade.Security.Code == Security.Code);
                        var entryPrice = trade.Trade.Price;

                         ((HustleEveryDayStrategyProperties) Params).Stoploss = entryPrice;

                     }
                     return;
                 }




             }
             else
             {
                 if (position.CurrentValue &amp;lt; 0)
                 {
                     if (Security.LastTrade.Price &amp;gt;= ((HustleEveryDayStrategyProperties)Params).Stoploss)
                     {
                         PlaceBuyMarketOrder(position.Security, position.CurrentValue);
                         return;
                     }

                     if (Security.LastTrade.Price &amp;lt;= ((HustleEveryDayStrategyProperties)Params).TakeProfit3)
                     {
                         PlaceBuyMarketOrder(position.Security, position.CurrentValue);
                         return;
                     }

                     if (Security.LastTrade.Price &amp;lt;= ((HustleEveryDayStrategyProperties)Params).TakeProfit2)
                     {
                         PlaceBuyMarketOrder(position.Security, decimal.Floor(0.5m * position.CurrentValue));
                         ((HustleEveryDayStrategyProperties)Params).Stoploss =
                             ((HustleEveryDayStrategyProperties)Params).TakeProfit1;

                         return;
                     }
                     if (Security.LastTrade.Price &amp;lt;= ((HustleEveryDayStrategyProperties)Params).TakeProfit1)
                     {

                         PlaceBuyMarketOrder(position.Security, decimal.Floor(0.33m * position.CurrentValue));

                         if (MyTrades.Any(t =&amp;gt; t.Trade.Security.Code == Security.Code))
                         {
                             var myTradesOrderedByDate = MyTrades.ToList().OrderBy(t =&amp;gt; t.Trade.Time);
                             var trade = myTradesOrderedByDate.Last(t =&amp;gt; t.Trade.Security.Code == Security.Code);
                             var entryPrice = trade.Trade.Price;

                             ((HustleEveryDayStrategyProperties)Params).Stoploss = entryPrice;

                         }
                         return;
                     }




                 }
             }
          
              
         }
          

       }


       private  void CheckForExitByTimeTargets()
       {

           this.AddInfoLog(&amp;quot;Выход по тайм-стопу&amp;quot;);
       
             foreach (var position in PositionManager.Positions)
             {
                 if(position.CurrentValue&amp;gt;0)
                 {
                     PlaceSellMarketOrder(position.Security,position.CurrentValue);

                 }
           
                 if (position.CurrentValue &amp;lt; 0)
                 {
                     PlaceBuyMarketOrder(position.Security, -position.CurrentValue);


                 }
                  

             }

       }

       protected void PlaceBuyMarketOrder(Security security, decimal volume)
       {
           var order = this.BuyAtMarket(volume);
           order.Security = security;

           order
                          .WhenChanged()
                          .Do(() =&amp;gt; this.AddInfoLog(&amp;quot;Изменилось остояние заявки&amp;quot;))
                          .Once()
                          .Apply(this);



           order
               .WhenRegistered()
               .Do(() =&amp;gt; this.AddInfoLog(&amp;quot;Заявка успешно зарегистрирована&amp;quot;))
               .Once()
               .Apply(this);

           order
               .WhenRegisterFailed()
               .Do(() =&amp;gt; this.AddInfoLog(&amp;quot;Заявка не принята биржей&amp;quot;))
               .Once()
               .Apply(this);

           order
               .WhenMatched()
               .Do(() =&amp;gt;
               {

                   this.AddInfoLog(&amp;quot;Заявка полностью исполнена&amp;quot;);
               })
               .Once()
               .Apply(this);

           // регистрирация заявки

           RegisterOrder(order);

       }
       protected void PlaceSellMarketOrder(Security security, decimal volume)
       {
           var order = this.SellAtMarket(volume);
           order.Security = security;
           order
                          .WhenChanged()
                          .Do(() =&amp;gt; this.AddInfoLog(&amp;quot;Изменилось остояние заявки&amp;quot;))
                          .Once()
                          .Apply(this);



           order
               .WhenRegistered()
               .Do(() =&amp;gt; this.AddInfoLog(&amp;quot;Заявка успешно зарегистрирована&amp;quot;))
               .Once()
               .Apply(this);

           order
               .WhenRegisterFailed()
               .Do(() =&amp;gt; this.AddInfoLog(&amp;quot;Заявка не принята биржей&amp;quot;))
               .Once()
               .Apply(this);

           order
               .WhenMatched()
               .Do(() =&amp;gt;
               {

                   this.AddInfoLog(&amp;quot;Заявка полностью исполнена&amp;quot;);
               })
               .Once()
               .Apply(this);

           // регистрирация заявки

           RegisterOrder(order);

       }
   

    }
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
</feed>