» » Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1

 

Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1

Автор: admin от 11-12-2018, 18:10, посмотрело: 55

Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1



В нашем блоге мы много пишем о технологиях и полезных инструментах, связанных с биржевой торговлей. Один из них – бесплатная платформа StockSharp
, которую можно использовать для профессиональной разработки торговых терминалов и торговых роботов на языке C#. В данной статье мы покажем, как использовать графический фреймворк, входящий в S#.API, с целью создания торгового терминала с возможностью запуска алгоритмических стратегий.SMARTcom от ITI Capital.


Создание проекта



Создадим новое WPF-приложение в Visual Studio:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


После чего необходимо добавить S#.API библиотеки. О том, как это сделать, можно узнать в документации. Оптимальный вариант – установка с помощью Nuget.



Так как все графические элементы S#.API созданы на базе DevExpress, а библиотеки DevExpress идут вместе с S#.API, глупо будет ими не воспользоваться. Перейдем в редактор окна MainWindow.xaml:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


Заменим Window на DXWindow, это нам понадобится для использования разных цветовых схем:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


Visual Studio нам сама предложит вставить необходимые библиотеки.



Разобьем окно на три части – сверху будет полоса с кнопками настройки подключений и подключения, внизу – окно с логами, а в середине все остальные панели. Проще всего так разбить окно с помощью LayoutControl от DevExpress.



В получившиеся три части мы и будем добавлять необходимые нам элементы.



<dx:DXWindow x:Class="ShellNew.MainWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
             xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
             mc:Ignorable="d"
             Title="MainWindow" Height="450" Width="800">
	<dxlc:LayoutControl Padding="0" Name="LayoutControlRoot" Orientation="Vertical">
		<dxlc:LayoutGroup HorizontalAlignment="Stretch" Height="25">
			<!-- верхняя часть-
		</dxlc:LayoutGroup>
		<dxlc:LayoutGroup HorizontalAlignment="Stretch" >
			<!-- центральная часть-
		</dxlc:LayoutGroup>
		<dxlc:LayoutGroup HorizontalAlignment="Stretch" >
			<!-- нижняя часть-
		</dxlc:LayoutGroup>
	</dxlc:LayoutControl>
</dx:DXWindow>


Настройка подключения к коннектору



Добавим две кнопки, одна кнопка настройки подключения, а вторая кнопка подключения. Для этого воспользуемся кнопкой SimpleButton от DevExpress. Кнопки будут расположены в верхней части приложения. В каждую кнопку поместим картинки, привычные по S#.Designer, S#.Data и S#.Terminal.



<dx:DXWindow x:Class="ShellNew.MainWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
             xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
             xmlns:xaml="http://schemas.stocksharp.com/xaml"
             mc:Ignorable="d"
             Title="MainWindow" Height="450" Width="800">
	<dxlc:LayoutControl Padding="0" Name="LayoutControlRoot" Orientation="Vertical">
		<dxlc:LayoutGroup HorizontalAlignment="Stretch" Height="25">
			<!-- верхняя часть-
			<dxlc:LayoutItem Width="40">
				<dx:SimpleButton x:Name="SettingsButton" Click="SettingsButton_Click" >
					<Image Source="{xaml:ThemedIcons Key=Settings}" Width="16" />
				</dx:SimpleButton>
			</dxlc:LayoutItem>
			<dxlc:LayoutItem Width="40">
				<dx:SimpleButton x:Name="ConnectButton" Click="ConnectButton_Click" >
					<Image Source="{xaml:ThemedIcons Key=Connect}" Width="16" />
				</dx:SimpleButton>
			</dxlc:LayoutItem>
		</dxlc:LayoutGroup>
		<dxlc:LayoutGroup HorizontalAlignment="Stretch" View="Tabs">
			<!-- центральная часть-
		</dxlc:LayoutGroup>
		<dxlc:LayoutGroup HorizontalAlignment="Stretch" >
			<!-- нижняя часть-
		</dxlc:LayoutGroup>
	</dxlc:LayoutControl>
</dx:DXWindow>


В верхнем правом углу экранной формы увидим такую картину:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


Двойным кликом на каждую кнопку создадим обработчики событий нажатия на кнопку. В коде MainWindow необходимо объявить коннектор, а также место и имя файла в котором будут храниться настройки коннектора.



public readonly Connector Connector;
private const string _dir = "Data";
private static readonly string _settingsFile = $@"{_dir}connection.xml";


В обработчике события нажатия на кнопку настроек коннектора будем открывать окно конфигурации коннектора и сохранять его в файл.



private void SettingsButton_Click(object sender, RoutedEventArgs e)
{
	if (Connector.Configure(this))
	{
		new XmlSerializer<SettingsStorage>().Serialize(Connector.Save(), _settingsFile);
	}
}


В конструкторе будем проверять, есть ли каталог и файл с настройками коннектора, и если он есть, будем его загружать в коннектор:



//----------------------------------------------------------------------------------
Directory.CreateDirectory(_dir);
Connector = new Connector();
if (File.Exists(_settingsFile))
{
	Connector.Load(new XmlSerializer<SettingsStorage>().Deserialize(_settingsFile));
}
//----------------------------------------------------------------------------------


Большинство объектов S#.API имеют методы Save и Load, с помощью которых можно сохранить и загрузить этот объект из XML-файла.



В методе обработчике нажатия на кнопку подключения подключаем коннектор.



		private void ConnectButton_Click(object sender, RoutedEventArgs e)
		{
			Connector.Connect();
		}


Теперь можно запустить программу и проверить ее.



Установка темной темы



Многие трейдеры предпочитают темные темы торговых приложений. Поэтому сразу делаем так, чтобы тема программы была темной. Для нужно найти файл App.xaml:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


И заменить в нем Application на charting:ExtendedBaseApplication, и Visual Studio нам сама предложит вставить необходимые библиотеки.



<charting:ExtendedBaseApplication
	x:Class="ShellNew.App"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:charting="http://schemas.stocksharp.com/xaml"
	StartupUri="MainWindow.xaml">
</charting:ExtendedBaseApplication>


А в файле App.xaml.cs нужно удалить «: Application».



namespace ShellNew
{
	/// <summary>
	/// Interaction logic for App.xaml
	/// </summary>
	public partial class App 
	{
	}
}


В конструкторе MainWindow пишем ApplicationThemeHelper.ApplicationThemeName = Theme.VS2017DarkName;



Полный код на текущий момент:



public partial class MainWindow
{
	public readonly Connector Connector;

	private const string _dir = "Data";
	private static readonly string _settingsFile = $@"{_dir}connection.xml";

	public MainWindow()
	{
		//----------------------------------------------------------------------------------
		ApplicationThemeHelper.ApplicationThemeName = Theme.VS2017DarkName;
		//----------------------------------------------------------------------------------
		Directory.CreateDirectory(_dir);
		Connector = new Connector();
		if (File.Exists(_settingsFile))
		{
			Connector.Load(new XmlSerializer<SettingsStorage>().Deserialize(_settingsFile));
		}
		//----------------------------------------------------------------------------------
		InitializeComponent();
	}

	private void SettingsButton_Click(object sender, RoutedEventArgs e)
	{
		if (Connector.Configure(this))
		{
			new XmlSerializer<SettingsStorage>().Serialize(Connector.Save(), _settingsFile);
		}
	}

	private void ConnectButton_Click(object sender, RoutedEventArgs e)
	{
		Connector.Connect();
	}
}


Запускаем для проверки темной темы:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


Создание панели инструментов



Добавим папку, где мы будем хранить все созданные нами контроллы, и назовем ее XAML. Добавим в нее свой первый UserControll, дадим ему имя SecurityGridControl.



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


В него добавляем один элемент SecurityPicker. В нем будут отображаться имеющиеся инструменты. По аналогии с главным окном будем использовать LayoutControl от DevExpress.



<UserControl
	x:Class="ShellNew.XAML.SecurityGridControl"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:xaml="http://schemas.stocksharp.com/xaml"
	mc:Ignorable="d"
	d:DesignHeight="450" d:DesignWidth="800">
	<xaml:SecurityPicker x:Name="SecPicker" />
</UserControl>


Перейдем в конструктор главного окна и изменим центральную часть в вид закладок. В одной из закладок расположим созданный нами контролл с SecurityPicker:



<dxlc:LayoutGroup HorizontalAlignment="Stretch" View="Tabs">
	<!-- центральная часть-
	<dxlc:LayoutGroup  Header="Securities">
		<myxaml:SecurityGridControl x:Name="SecurityPanel" />
	</dxlc:LayoutGroup>
</dxlc:LayoutGroup>


Теперь, когда у нас есть панель инструментов, надо задать ей источник данных, в нашем случае это коннектор. Можно было просто в конструкторе MainWindow написать

SecurityPanel.SecPicker.SecurityProvider = Connector;
.



Но не стоит засорять MainWindow кодом, который к нему не относится. Поэтому создадим статическую переменную Instance а в конструкторе MainWindow присвою ему значение MainWindow:



…
public static MainWindow Instance;
…
Instance = this;
…


Теперь в любом месте нашей программы мы можем обращаться к свойствам MainWindow через код MainWindow.Instance.XXX.



В конструкторе SecurityGridControl таким образом указываем Connector как источник данных:



public SecurityGridControl()
{
	InitializeComponent();
	SecPicker.SecurityProvider = MainWindow.Instance.Connector;
}


Запустим для проверки:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


Добавление логирования



Работу программы, коннектора или робота необходимо контролировать. Для этого в S#.API есть специальный класс LogManager. Данный класс принимает сообщения от источников и передает их в слушатели. В нашем случае источниками будут Connector, стратегии и т.д., а слушателем будет файл и панель логов.



В коде MainWindow объявляем объект LogManager и место, где он будет храниться:



public readonly LogManager LogManager;
private static readonly string _logsDir = $@"{_dir}Logs";


В конструкторе MainWindow создаем LogManager, задаем ему источник Connector и файл слушателя:



//----------------------------------------------------------------------------------
LogManager = new LogManager();
LogManager.Sources.Add(Connector);
LogManager.Listeners.Add(new FileLogListener
{
	SeparateByDates = SeparateByDateModes.SubDirectories,
	LogDirectory = _logsDir
});
//----------------------------------------------------------------------------------


По аналогии с панелью инструментов создадим, панель логов в папку XAML добавляем еще один UserControl. Дадим ему имя MonitorControl. В него добавим элемент Monitor.



<UserControl
	x:Class="ShellNew.XAML.MonitorControl"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:xaml="http://schemas.stocksharp.com/xaml"
	mc:Ignorable="d"
	d:DesignHeight="450" d:DesignWidth="800">
	<xaml:Monitor x:Name="Monitor" />
</UserControl>


В конструкторе MonitorControl зададим в LogManager еще и Monitor как слушателя:



public MonitorControl()
{
	InitializeComponent();
	MainWindow.Instance.LogManager.Listeners.Add(new GuiLogListener(Monitor));
}


В нижнюю часть MainWindow добавляем созданный MonitorControl:



<dxlc:LayoutGroup HorizontalAlignment="Stretch" dxlc:LayoutControl.AllowVerticalSizing="True">
	<!-- нижняя часть-
	<myxaml:MonitorControl x:Name="MonitorControl" />
</dxlc:LayoutGroup>


Запускаем для проверки:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


Создание панели стаканов



По аналогии с предыдущими панелями создадим панель стаканов, в папку XAML добавляем еще один UserControl. Дадим ему имя MarketDepthControl.



В MainWindow мы уже использовали LayoutControl, в этом контроле тоже воспользуемся LayoutControl. Разобьем панель на две части по горизонтали:



 <UserControl
	x:Class="ShellNew.XAML.MarketDepthControl"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
	mc:Ignorable="d">
	<dxlc:LayoutControl Padding="0" Name="LayoutControlRoot" Orientation="Horizontal">
		<dxlc:LayoutGroup>
		<!--Left-
		</dxlc:LayoutGroup>
		<dxlc:LayoutGroup Orientation="Vertical" dxlc:LayoutControl.AllowHorizontalSizing="True">
		<!--Rigth-
		</dxlc:LayoutGroup>
	</dxlc:LayoutControl>
</UserControl>


В левую часть добавим SecurityPicker – с ним мы встречались, когда создавали панель инструментов.



<dxlc:LayoutGroup>
	<xaml:SecurityPicker x:Name="SecPicker" SecuritySelected="SecPicker_SecuritySelected" />
</dxlc:LayoutGroup>
Правую часть разобьем на части по вертикали. Сверху правой части будет стакан:
<dxlc:LayoutGroup Orientation="Vertical"
                  dxlc:LayoutControl.AllowHorizontalSizing="True">
	<dxlc:LayoutItem VerticalAlignment="Stretch">
		<xaml:MarketDepthControl x:Name="MarketDepth" MaxHeight="2000"
                         Selectionchanged="MarketDepth_Selectionchanged" />
	</dxlc:LayoutItem>
</dxlc:LayoutGroup>


У MarketDepthControl необходимо задать какое-нибудь значение MaxHeight, иначе приложение не будет запускаться.



Под стаканом расположим элементы задания портфеля, цены, и объёма заявки:



<dxlc:LayoutItem Label="Portfolio" Height="20">
	<xaml:PortfolioComboBox x:Name="PortfolioComboBox" />
</dxlc:LayoutItem>
<dxlc:LayoutItem Label="Price" Height="20">
	<dxe:SpinEdit MinValue="0" Name="SpinEditPrice" />
</dxlc:LayoutItem>
<dxlc:LayoutItem Label="Volume" Height="20">
	<dxe:SpinEdit MinValue="0" Name="SpinEditVolume" />
</dxlc:LayoutItem>


Здесь стоит отметить свойство Label у LayoutItem, оно позволяет задать текст перед элементом. А также элемент SpinEdit от DevExpress в котором удобно задавать численные значения. Выглядят эти элементы следующим образом:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


Еще ниже расположим кнопки купить и продать:



<dxlc:LayoutGroup Orientation="Horizontal" Height="20" VerticalAlignment="Stretch">
	<dxlc:LayoutItem VerticalAlignment="Stretch">
		<dx:SimpleButton Content="Buy" x:Name="BuyButton" Click="BuyButton_Click" />
	</dxlc:LayoutItem>
	<dxlc:LayoutItem VerticalAlignment="Stretch">
		<dx:SimpleButton Content="Sell" x:Name="SelltButton" Click="SelltButton_Click" />
	</dxlc:LayoutItem>
</dxlc:LayoutGroup>


Полный код:



<UserControl
	x:Class="ShellNew.XAML.MarketDepthControl"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
	xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
	xmlns:xaml="http://schemas.stocksharp.com/xaml"
	xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
	mc:Ignorable="d">
	<dxlc:LayoutControl Padding="0" Name="LayoutControlRoot" Orientation="Horizontal">
		<dxlc:LayoutGroup>
			<xaml:SecurityPicker x:Name="SecPicker" 
								 SecuritySelected="SecPicker_SecuritySelected" />
		</dxlc:LayoutGroup>
		<dxlc:LayoutGroup Orientation="Vertical" 
						  dxlc:LayoutControl.AllowHorizontalSizing="True">
			<dxlc:LayoutItem VerticalAlignment="Stretch">
				<xaml:MarketDepthControl x:Name="MarketDepth" MaxHeight="2000" 
										 Selectionchanged="MarketDepth_Selectionchanged" />
			</dxlc:LayoutItem>
			<dxlc:LayoutItem Label="Portfolio" Height="20">
				<xaml:PortfolioComboBox x:Name="PortfolioComboBox" />
			</dxlc:LayoutItem>
			<dxlc:LayoutItem Label="Price" Height="20">
				<dxe:SpinEdit MinValue="0" Name="SpinEditPrice" />
			</dxlc:LayoutItem>
			<dxlc:LayoutItem Label="Volume" Height="20">
				<dxe:SpinEdit MinValue="0" Name="SpinEditVolume" />
			</dxlc:LayoutItem>
			<dxlc:LayoutGroup Orientation="Horizontal" Height="20" 
							  VerticalAlignment="Stretch">
				<dxlc:LayoutItem VerticalAlignment="Stretch">
					<dx:SimpleButton Content="Buy" x:Name="BuyButton" 
									 Click="BuyButton_Click" />
				</dxlc:LayoutItem>
				<dxlc:LayoutItem VerticalAlignment="Stretch">
					<dx:SimpleButton Content="Sell" x:Name="SelltButton" 
									 Click="SelltButton_Click" />
				</dxlc:LayoutItem>
			</dxlc:LayoutGroup>
		</dxlc:LayoutGroup>
	</dxlc:LayoutControl>
</UserControl>


В конструкторе MarketDepthControl зададим источник инструментов для SecurityPicker и источник портфелей для PortfolioComboBox, в нашем случае это будет Connector:



public MarketDepthControl()
{
	InitializeComponent();
	SecPicker.SecurityProvider = MainWindow.Instance.Connector;
	PortfolioComboBox.Portfolios = new PortfolioDataSource(MainWindow.Instance.Connector);
}


Создадим обработчик события выделения инструмента в SecurityPicker. В нем проверяем не равен ли нулю полученный инструмент. Если он не равен нулю, сохраняем полученный инструмент в локальную переменную, нам он пригодится при обновлении стакана. После чего очищаем и регистрируем полученный инструмент в Connector на получение стакана с помощью метода RegisterMarketDepth. С помощью метода GetMarketDepth получаем текущий стакан по инструменту, чтобы им обновить MarketDepthControl.



private Security _selectedSecurity;
private void SecPicker_SecuritySelected(Security security)
{
	if (security == null) return;
	_selectedSecurity = security;
	MainWindow.Instance.Connector.RegisterMarketDepth(_selectedSecurity);
	var marketDepth = MainWindow.Instance.Connector.GetMarketDepth(_selectedSecurity);
	MarketDepth.UpdateDepth(marketDepth);
}


Чтобы стакан постоянно обновлялся в конструкторе MarketDepthControl, подпишемся на событие изменения стакана MarketDepthChanged у коннектора. В обработчике этого события будем проверять, какому инструменту принадлежит полученный стакан, и если он принадлежит выделенному инструменту в SecurityPicker, то обновляем им: MarketDepthControl.



public MarketDepthControl()
{
	InitializeComponent();
	SecPicker.SecurityProvider = MainWindow.Instance.Connector;
	PortfolioComboBox.Portfolios = new PortfolioDataSource(MainWindow.Instance.Connector);
	MainWindow.Instance.Connector.MarketDepthChanged += Connector_MarketDepthChanged;
}

private void Connector_MarketDepthChanged(MarketDepth marketDepth)
{
	if (_selectedSecurity == null || 
		marketDepth.Security != _selectedSecurity) return;
	MarketDepth.UpdateDepth(marketDepth);
}


В центральную части MainWindow добавляем созданную панель MarketDepthControl:



<dxlc:LayoutGroup HorizontalAlignment="Stretch" View="Tabs">
	<!-- центральная часть-
	<dxlc:LayoutGroup  Header="Securities">
		<myxaml:SecurityGridControl x:Name="SecurityPanel" />
	</dxlc:LayoutGroup>
	<dxlc:LayoutGroup  Header="Portfolios">
		<myxaml:PortfolioGridControl x:Name="PortfolioGridControl" />
	</dxlc:LayoutGroup>
	<dxlc:LayoutGroup  Header="Orders">
		<myxaml:OrderGridControl x:Name="OrderGridControl" />
	</dxlc:LayoutGroup>
	<dxlc:LayoutGroup  Header="MyTrades">
		<myxaml:MyTradeGridControl x:Name="MyTradeGridControl" />
	</dxlc:LayoutGroup>
	<dxlc:LayoutGroup  Header="MarketDepth">
		<myxaml:MarketDepthControl x:Name="MarketDepthControl" />
	</dxlc:LayoutGroup>
</dxlc:LayoutGroup>


На данном этапе можно запустить программу и проверить работу обновления стаканов.

Создадим обработчика события нажатия на кнопки купить и продать. В каждом обработчике создаем Order, в нем указываем инструмент выбранный в SecurityPicker, портфель выбранный в PortfolioComboBox, объём и цену из соответствующих SpinEdit. Регистрируем заявку в Connector с помощью метода RegisterOrder.



private void BuyButton_Click(object sender, RoutedEventArgs e)
{
	Order order = new Order()
	{
		Security = _selectedSecurity,
		Portfolio = PortfolioComboBox.SelectedPortfolio,
		Volume = SpinEditVolume.Value,
		Price = SpinEditPrice.Value,
		Direction = StockSharp.Messages.Sides.Buy,
	};
	MainWindow.Instance.Connector.RegisterOrder(order);
}

private void SelltButton_Click(object sender, RoutedEventArgs e)
{
	Order order = new Order()
	{
		Security = _selectedSecurity,
		Portfolio = PortfolioComboBox.SelectedPortfolio,
		Volume = SpinEditVolume.Value,
		Price = SpinEditPrice.Value,
		Direction = StockSharp.Messages.Sides.Sell,
	};
	MainWindow.Instance.Connector.RegisterOrder(order);
}


Оба обработчика отличаются только направлением заявки.



Сделаем чтобы при выделении котировки в стакане значение SpinEditPrice менялось на цену выделенной котировки. Для этого создадим обработчик события Selectionchanged у MarketDepthControl. В котором будем обновлять значение SpinEditPrice ценой выделенной котировки если выделенная котировка не равна нулю.



private void MarketDepth_Selectionchanged(object sender, 
	GridSelectionchangedEventArgs e)
{
	if (MarketDepth.SelectedQuote == null)
		return;
	SpinEditPrice.Value = MarketDepth.SelectedQuote.Price;
}


Запускаем для проверки:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


Сохранение маркет-данных



Для сохранения портфелей, инструментов, площадок нам необходим класс CsvEntityRegistry. В него надо переделать место хранения сущностей и вызвать метод Init, для их загрузки.



	_csvEntityRegistry = new CsvEntityRegistry(_csvEntityRegistryDir);
	_csvEntityRegistry.Init();


Для сохранения свечей, сделок и т.д. нам понадобится StorageRegistry:



	_storageRegistry = new StorageRegistry
	{
		DefaultDrive = new LocalMarketDataDrive(_storageRegistryDir),
	};


Также нам понадобится реестр хранилищ-снэпшотов SnapshotRegistry:



_snapshotRegistry = new SnapshotRegistry(_snapshotRegistryDir);


Все это мы передаем в Connector при его создании:



Connector = new Connector(_csvEntityRegistry, _storageRegistry, _snapshotRegistry)
{
	IsRestoreSubscriptionOnReconnect = true,
	StorageAdapter = { DaysLoad = TimeSpan.FromDays(3) },
};
Connector.LookupAll();


Здесь мы также указали, что Connector будет переподключаться при разрыве подключения, а также указали сколько дней истории необходимо загружать. Строка Connector.LookupAll(); запрашивает имеющиеся данные:



//----------------------------------------------------------------------------------
Directory.CreateDirectory(_dir);

_csvEntityRegistry = new CsvEntityRegistry(_csvEntityRegistryDir);
_csvEntityRegistry.Init();
_storageRegistry = new StorageRegistry
{
	DefaultDrive = new LocalMarketDataDrive(_storageRegistryDir),
};
_snapshotRegistry = new SnapshotRegistry(_snapshotRegistryDir);
Connector = new Connector(_csvEntityRegistry, _storageRegistry, _snapshotRegistry)
	{
		IsRestoreSubscriptionOnReconnect = true,
		StorageAdapter = { DaysLoad = TimeSpan.FromDays(3) },
	};
Connector.LookupAll();

if (File.Exists(_settingsFile))
{
		Connector.Load(new XmlSerializer<SettingsStorage>().Deserialize(_settingsFile));
}
//----------------------------------------------------------------------------------


После загрузки приложения перейдя в папку Data мы увидим, что появились новые папки:



Пишем торговых роботов с помощью графического фреймворка StockSharp. Часть 1


При повторном подключении панели инструментов и портфелей уже будут заполнены.



Мы плавно подошли к окончанию первой части. На данном этапе программа позволяет выводить на экран все доступные нам маркет-данные. В следующей части будет продемонстрирована самое лакомое — а именно торговля как в ручном, так и в автоматическом режиме.



Продолжение следует...



Автор: Иван Залуцкий

Источник: Хабр / Интересные публикации

Категория: Программирование

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *