Escrevemos robôs de negociação usando a estrutura gráfica StockSharp. Parte 1



Em nosso blog, escrevemos muito sobre tecnologias e ferramentas úteis relacionadas à negociação de ações. Uma delas é a plataforma StockSharp gratuita, que pode ser usada para o desenvolvimento profissional de terminais de negociação e robôs de negociação em C #. Neste artigo, mostraremos como usar a estrutura gráfica incluída no S # .API para criar um terminal de negociação com a capacidade de executar estratégias algorítmicas.

O que é necessário


  1. Visual Studio 2017 (Comunidade, versão gratuita), nele vamos programar.
  2. Conexão à negociação na bolsa, nos exemplos deste texto, a interface SMARTcom da ITI Capital é usada .

Criação de projeto


Crie um novo aplicativo WPF no Visual Studio:



Então você precisa adicionar a biblioteca S # .API. Você pode descobrir como fazer isso na documentação . A melhor opção é instalar usando o Nuget.

Como todos os elementos gráficos do S # .API são baseados no DevExpress, e as bibliotecas do DevExpress vêm com o S # .API, seria tolice não usá-los. Vamos para o editor de janelas MainWindow.xaml:



Substitua Window pelo DXWindow, será necessário usar diferentes esquemas de cores:



O próprio Visual Studio nos oferecerá a inserção das bibliotecas necessárias.

Dividiremos a janela em três partes - na parte superior, haverá uma faixa com botões para configurar conexões e conexões; na parte inferior, haverá uma janela com troncos e, no meio, todos os outros painéis. A maneira mais fácil de quebrar uma janela é com o LayoutControl do DevExpress.

Nas três partes resultantes, adicionaremos os elementos que precisamos.

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

Configurando uma Conexão com um Conector


Adicione dois botões, um é o botão de configurações de conexão e o segundo é o botão de conexão. Para fazer isso, use o botão SimpleButton do DevExpress. Os botões estarão localizados na parte superior do aplicativo. Em cada botão, colocamos as figuras familiares de S # .Designer , S # .Data e 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> 

No canto superior direito da tela, veremos a seguinte figura:



Clique duas vezes em cada botão para criar manipuladores de eventos para clicar no botão. No código da MainWindow, você deve declarar o conector, bem como o local e o nome do arquivo no qual as configurações do conector serão armazenadas.

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

No manipulador de eventos para clicar no botão de configurações do conector, abriremos a janela de configuração do conector e a salvaremos em um arquivo.

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

No construtor, verificaremos se há um diretório e um arquivo com as configurações do conector e, se houver, carregaremos no conector:

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

A maioria dos objetos .API do S # possui métodos Save and Load que podem ser usados ​​para salvar e carregar esse objeto de um arquivo XML.

No manipulador de métodos, clicando no botão conectar, conectamos o conector.

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

Agora você pode executar o programa e verificá-lo.

Definindo um tema sombrio


Muitos traders preferem temas obscuros a aplicativos de negociação. Portanto, imediatamente escurecemos o tema do programa. Para você precisar encontrar o arquivo App.xaml:



E substitua Application por gráficos: ExtendedBaseApplication, e o próprio Visual Studio nos oferecerá a inserção das bibliotecas necessárias.

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

E no arquivo App.xaml.cs, você precisa excluir ": Application".

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

No construtor de MainWindow, escreva ApplicationThemeHelper.ApplicationThemeName = Theme.VS2017DarkName;

Código completo no momento:

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

Execute para verificar o tópico obscuro:



Criar barra de ferramentas


Adicione uma pasta na qual armazenaremos todos os controles que criamos e chame-a de XAML. Adicione nosso primeiro UserControll, atribua o nome SecurityGridControl.



Nós adicionamos um elemento SecurityPicker a ele. Ele exibirá as ferramentas disponíveis. Por analogia com a janela principal, usaremos o LayoutControl do 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> 

Vamos ao designer da janela principal e alteramos a parte central para a exibição de marcadores. Em um dos favoritos, colocaremos o controlador que criamos com o SecurityPicker:

 <dxlc:LayoutGroup HorizontalAlignment="Stretch" View="Tabs"> <!--  --> <dxlc:LayoutGroup Header="Securities"> <myxaml:SecurityGridControl x:Name="SecurityPanel" /> </dxlc:LayoutGroup> </dxlc:LayoutGroup> 

Agora que temos a barra de ferramentas, precisamos fornecer uma fonte de dados, no nosso caso, é um conector. Você pode simplesmente MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
no construtor MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
.

Mas você não deve entupir o MainWindow com código que não se aplica a ele. Portanto, criaremos a variável estática Instance e atribuiremos MainWindow a ela no construtor MainWindow:

 public static MainWindow Instance; … Instance = this; … 

Agora, em qualquer lugar do nosso programa, podemos acessar as propriedades do MainWindow através do código MainWindow.Instance.XXX.

No construtor SecurityGridControl, dessa maneira, especificamos o Connector como uma fonte de dados:

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

Execute para verificar:



Adicionando log


O programa, conector ou robô deve ser controlado. Para isso, o S # .API possui uma classe especial do LogManager. Essa classe recebe mensagens de fontes e as passa para ouvintes. No nosso caso, as fontes serão Connector, estratégias, etc., e o ouvinte será um arquivo e um painel de log.

No código MainWindow, declaramos o objeto LogManager e o local em que ele será armazenado:

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

No construtor MainWindow, crie um LogManager, defina a fonte do Connector e o arquivo ouvinte para ele:

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

Por analogia com a barra de ferramentas, crie um painel de log na pasta XAML, adicione outro UserControl. Atribua a ele o nome MonitorControl. Adicione o elemento Monitor a ele.

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

No construtor MonitorControl, defina LogManager como Monitor como um ouvinte:

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

Adicione o MonitorControl criado à parte inferior do MainWindow:

 <dxlc:LayoutGroup HorizontalAlignment="Stretch" dxlc:LayoutControl.AllowVerticalSizing="True"> <!--  --> <myxaml:MonitorControl x:Name="MonitorControl" /> </dxlc:LayoutGroup> 

Execute para verificar:



Crie um painel de vidro


Por analogia com os painéis anteriores, crie um painel de vidro e adicione outro UserControl à pasta XAML. Atribua o nome MarketDepthControl.

No MainWindow já usamos LayoutControl, nesse controle também usaremos LayoutControl. Dividimos o painel em duas partes horizontalmente:

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

Adicione o SecurityPicker ao lado esquerdo - nos encontramos com ele quando criamos a barra de ferramentas.

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

O MarketDepthControl precisa definir um valor MaxHeight, caso contrário, o aplicativo não será iniciado.

Sob o vidro, colocaremos os elementos da tarefa, preço e volume do pedido do portfólio:

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

Vale ressaltar a propriedade Label de LayoutItem, que permite definir o texto na frente do elemento. Assim como o elemento SpinEdit do DevExpress, no qual é conveniente definir valores numéricos. Esses elementos têm a seguinte aparência:



Abaixo, colocaremos os botões de compra e venda:

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

Código completo:

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

No construtor MarketDepthControl, defina a fonte de ferramentas para SecurityPicker e a fonte de portfólios para PortfolioComboBox; no nosso caso, será Connector:

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

Crie um manipulador de eventos de seleção de ferramentas no SecurityPicker. Nele, verificamos se a ferramenta recebida não é igual a zero. Se não for igual a zero, salvamos a ferramenta recebida em uma variável local; será útil para nós ao atualizar o vidro. Em seguida, limpamos e registramos a ferramenta recebida no Conector para receber um copo usando o método RegisterMarketDepth. Usando o método GetMarketDepth, obtemos o vidro atual do instrumento para atualizar o MarketDepthControl com ele.

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

Para que o vidro seja atualizado constantemente no construtor MarketDepthControl, inscrevamos o evento de alteração de vidro MarketDepthChanged no conector. No manipulador deste evento, verificaremos a qual ferramenta o vidro recebido pertence e, se ele pertence à ferramenta selecionada no SecurityPicker, atualizamos: 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); } 

Na parte central do MainWindow, adicione o painel MarketDepthControl criado:

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

Nesta fase, você pode executar o programa e verificar a operação da atualização de óculos.
Crie um manipulador de eventos para clicar nos botões de compra e venda. Em cada manipulador, criamos um Pedido, nele indicamos a ferramenta selecionada no SecurityPicker, o portfólio selecionado no PortfolioComboBox, volume e preço do SpinEdit correspondente. Registre o aplicativo no Connector usando o método 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); } 

Ambos os processadores diferem apenas na direção do aplicativo.

Vamos alterar o valor de SpinEditPrice pelo preço da cotação selecionada ao selecionar cotações em um copo. Para fazer isso, crie um manipulador de eventos SelectionChanged para MarketDepthControl. No qual atualizaremos o valor de SpinEditPrice ao preço da cotação selecionada, se a cotação selecionada não for igual a zero.

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

Execute para verificar:



Salvando dados do mercado


Para salvar portfólios, ferramentas, plataformas, precisamos da classe CsvEntityRegistry. É necessário refazer o local de armazenamento da entidade e chamar o método Init para carregá-los.

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

Para economizar velas, promoções etc. precisamos de StorageRegistry:

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

Também precisamos do registro SnapshotRegistry de lojas de instantâneos:

 _snapshotRegistry = new SnapshotRegistry(_snapshotRegistryDir); 

Tudo isso passamos para o Connector quando ele é criado:

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

Aqui também indicamos que o Conector será reconectado quando a conexão for desconectada e também indicará quantos dias de histórico será baixado. String Connector.LookupAll (); solicita dados disponíveis:

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

Depois de carregar o aplicativo, indo para a pasta Dados, veremos que novas pastas apareceram:



Ao reconectar, as barras de ferramentas e portfólios já estarão preenchidos.

Aproximamos o final da primeira parte sem problemas. Nesta fase, o programa permite exibir todos os dados de mercado disponíveis para nós. A próxima parte demonstrará o mais delicioso - ou seja, negociar no modo manual e automático.

Para continuar ...

Autor : Ivan Zalutsky

Source: https://habr.com/ru/post/pt432812/


All Articles