Собственно сабж
Основная задача автоматического управления вкладками из робота это упрощение реализации арбитражных стратегий, путем использования кода управления позициями вкладкой арбитражируемого инструметна. В прочем это не мешает использовать данный подход и в прочих стратегиях, например для автоматического создания вкладок верхнего таймфрейма или обращения к данным разных способов построения чарта. Если в случае арбитража использование такого подхода - необходимость, то в случае классических стратегий лишь упрощение предварительной настройки робота перед торговлей.
1. Реализация :
В конструкторе робота мы подписываемся на событие создания нового сервера в классе менеджера серверов ServerMaster
public ClassicArbitrageSemiHFT(string name, StartProgram startProgram) : base(name, startProgram)
{
ServerMaster.ServerCreateEvent += ServerMaster_ServerCreateEvent;
}
Метод реализации логики на данное событие принимает в качестве аргумента созданный сервер, а сама логика метода предполагает подписку на события созданного сервера, но мы должны использовать несколько серверов при этом их количество нам не известно, и все события на которые мы подпишемся так же должны возвращать тип сервера от которого пришло событие. Для этого мы создадим класс-событийную прослойку в который запишем тип сервера и подпишемся на события экземпляров нового класса.
2. Реализация класса-событийной прослойки:
public class ServerTyped
{
public ServerType Type;
public IServer Server;
public ServerConnectStatus ServerStatus;
public bool isActive = false;
public List<Portfolio> Portfolios;
public ServerTyped(IServer server)
{
Server = server;
Type = server.ServerType;
SubscribeEvents();
}
private void SubscribeEvents()
{
Server.ConnectStatusChangeEvent += Serv_ConnectStatusChangeEvent;
Server.NeadToReconnectEvent += Serv_NeadToReconnectEvent;
Server.PortfoliosChangeEvent += Serv_PortfoliosChangeEvent;
Server.SecuritiesChangeEvent += Serv_SecuritiesChangeEvent;
Server.NewMyTradeEvent += Serv_NewMyTradeEvent;
Server.NewOrderIncomeEvent += Serv_NewOrderIncomeEvent;
Server.NewBidAscIncomeEvent += Serv_NewBidAscIncomeEvent;
Server.ConnectStatusChangeEvent += Server_ConnectStatusChangeEvent;
}
private void Server_ConnectStatusChangeEvent(string obj)
{
ServerStatus = Server.ServerStatus;
}
private void Serv_NewBidAscIncomeEvent(decimal arg1, decimal arg2, Security arg3)
{
NewBidAscIncomeEvent(Type, arg1, arg2, arg3);
}
private void Serv_NewOrderIncomeEvent(Order obj)
{
NewOrderIncomeEvent(Type, obj);
}
private void Serv_NewMyTradeEvent(MyTrade obj)
{
NewMyTradeEvent(Type, obj);
}
private void Serv_SecuritiesChangeEvent(List<Security> obj)
{
SecuritiesChangeEvent(Type, obj);
}
private void Serv_PortfoliosChangeEvent(List<Portfolio> obj)
{
PortfoliosChangeEvent(Type, obj);
}
private void Serv_NeadToReconnectEvent()
{
NeadToReconnectEvent(Type);
}
private void Serv_ConnectStatusChangeEvent(string obj)
{
ConnectStatusChangeEvent(Type, obj);
}
public event Action<ServerType, decimal, decimal, Security> NewBidAscIncomeEvent;
public event Action<ServerType, Order> NewOrderIncomeEvent;
public event Action<ServerType, MyTrade> NewMyTradeEvent;
public event Action<ServerType, List<Security>> SecuritiesChangeEvent;
public event Action<ServerType, List<Portfolio>> PortfoliosChangeEvent;
public event Action<ServerType> NeadToReconnectEvent;
public event Action<ServerType, string> ConnectStatusChangeEvent;
public void StopServer()
{
Server.StopServer();
}
public void StartServer()
{
Server.StartServer();
}
}
3. Теперь когда мы имеем такой класс реализуем логику обработки события создания нового сервера из пункта 1, а так же сразу создадим список серверов и обработаем их события ориентируясь на типы серверов данных событий.
private void ServerMaster_ServerCreateEvent(IServer server)
{
if (serversList != null && serversList.Count > 0)
foreach (var serv in serversList)
if (serv == server)
return;
serversList.Add(new ServerTyped(server) { });
serversList.Last().ConnectStatusChangeEvent += ClassicArbitrageHFT_ConnectStatusChangeEvent;
serversList.Last().NeadToReconnectEvent += ClassicArbitrageHFT_NeadToReconnectEvent;
}
private void ClassicArbitrageHFT_ConnectStatusChangeEvent(ServerType type, string obj)
{
foreach (var serv in serversList.Where(x => x.isActive == false && x.Type == type))
if (serv.ServerStatus == ServerConnectStatus.Connect)
{
serv.isActive = true;
serv.PortfoliosChangeEvent += Serv_PortfoliosChangeEvent;
serv.SecuritiesChangeEvent += Serv_SecuritiesChangeEvent;
serv.NewMyTradeEvent += Serv_NewMyTradeEvent;
serv.NewOrderIncomeEvent += Serv_NewOrderIncomeEvent;
serv.NewBidAscIncomeEvent += Serv_NewBidAscIncomeEvent;
}
}
private void ClassicArbitrageHFT_NeadToReconnectEvent(ServerType type)
{
foreach (var serv in serversList.Where(x => x.Type == type))
{
serv.StopServer();
serv.StartServer();
}
}
Сами события обрабатываются согласно логике вашей стратегии, но все из них уже принимают в качестве параметра тип сервера на котором сработало событие.
4. Создание вкладки и управление ее параметрами из робота. На одном или нескольких событий сервера могут быть соблюдены условия создания или изменения вкладки. Для этого мы применим следующий подход:
if (TabsSimple.Where(x => x.Securiti == master_sec).Count() == 0)
{
TabCreate(BotTabType.Simple);
var conCandles = TabsSimple.Last().Connector;
conCandles.ServerType = masterInstrument.Type;
conCandles.PortfolioName = masterPortfolio;
conCandles.TimeFrameBuilder.CandleCreateMethodType = CandleCreateMethodType.Simple;
conCandles.TimeFrame = TimeFrame.Min10;
conCandles.NamePaper = master_sec.Name;
while (TabsSimple.Last().IsReadyToTrade == false)
{
Thread.Sleep(50);
}
}
if (TabsSimple.Where(x => x.Securiti == slave_sec).Count() == 0) { TabCreate(BotTabType.Simple); var conCandles = TabsSimple.Last().Connector; conCandles.ServerType = slaveInstrument.Type; conCandles.PortfolioName = slavePortfolio; conCandles.TimeFrameBuilder.CandleCreateMethodType = CandleCreateMethodType.Simple; conCandles.TimeFrame = TimeFrame.Min10; conCandles.NamePaper = slave_sec.Name; while (TabsSimple.Last().IsReadyToTrade == false) { Thread.Sleep(50); } }
var newTP = new TradingPair() { MasterSymbol = masterInstrument, SlaveSymbol = slaveInstrument, master_Tab = TabsSimple.Find(x => x.Connector.Security.Name == master_sec.Name), slave_Tab = TabsSimple.Find(x => x.Connector.Security.Name == slave_sec.Name) }; if (!tradingPairsList.Contains(newTP)) { tradingPairsList.Add(newTP); TabsSimple.Find(x => x.Securiti == master_sec).CandleUpdateEvent += _tab1_CandleUpdateEvent; TabsSimple.Find(x => x.Securiti == slave_sec).CandleUpdateEvent += _tab2_CandleUpdateEvent; TabsSimple.Find(x => x.Securiti == master_sec).CandleFinishedEvent += _tab1_CandleUpdateEvent; TabsSimple.Find(x => x.Securiti == slave_sec).CandleFinishedEvent += _tab2_CandleUpdateEvent; }
Вот так просто в 4 шага мы получаем реализацию управления вкладками из бота. Я не претендую на истину в последней инстанции, возможно есть более элегантное решение. Но, в случае использования моего кода целиком или частично, вы не должны использовать нижнее подчеркивание в началах имен приватных членах класса.
ООО «ВАН ТЕХНОЛОГИИ»т: +7 953 769 56 45
* Торговля на финансовых рынках связана с риском, который лежит на Вас.
* Ничто из написанного на сайте o-s-a.net не является рекомендацией.
* Если Вы этого не понимаете, не читайте этот сайт, ничего не покупайте.