Часть 3.1. Добавление своих стратегий.
Эта история полна нюансов.
В шелле хорошо показано, на примере одной стратегии как все работает и т.д.
Добавить свою взамен существующей тоже легко - меняем да и все. Либо по-варварски вставляем в существующую новые внутренности.
Но тут не так все гибко, чтобы наряду с существующими в два щелчка добавить новые стратегии и чтобы все прекрасно работало и сохранялось.
Можно чуть менее чем полностью переделать SettingsEngine, половину кода связанного с добавлением стратегий, и только потом добавлять какие угодно новые стратегии в два щелчка.
А можно сделать минимум изменений, прикрутив маленькие костыли и затем добавлять новые стратегии не в 2 а в 6 щелчков, о чем и пойдет речь дальше.
Я уже подготовил небольшую почву, наподобие той, про которую было во 2-ой части. Когда мне удастся подружиться с ТФС, эти изменения уже будут в шелле.
Может показаться, что кода много, но на самом деле там 90% копи паст.
Добавляем заготовку для стратегии, для параметров и параметров тестирования, которые когда-нибудь наполним содержанием.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Robot.Strategies
{
public class HustleEveryDayStrategyProperties :BaseShellStrategyProperties
{
}
public class HustleEveryDayStrategyTestingProperties:BaseShellTestingProperties
{
}
public class HustleEveryDayStrategy:BaseShellStrategy
{
}
}
Идем в SettingsEngine, добавляем методы для сохранения и загрузки параметров для нового типа стратегий.
private const string HustleEveryDayStrategies = @"HustleEveryDayStrategies.xml";
private const string TestingHustleEveryDayStrategies = @"TestingHustleEveryDayStrategies.xml";
public void SaveHustleEveryDayStrategiesProperties(List<HustleEveryDayStrategyProperties> properties)
{
this.AddInfoLog("Сохранение стратегий в {0}", HustleEveryDayStrategies);
using (var writer = new StreamWriter(HustleEveryDayStrategies, false))
{
var mySerializer = new XmlSerializer(typeof(List<HustleEveryDayStrategyProperties>));
mySerializer.Serialize(writer, properties);
}
}
public List<HustleEveryDayStrategyProperties> LoadHustleEveryDayStrategiesProperties()
{
this.AddInfoLog("Загрузка стратегий из {0}", HustleEveryDayStrategies);
var result = new List<HustleEveryDayStrategyProperties>();
if (File.Exists(HustleEveryDayStrategies))
{
try
{
using (var reader = new StreamReader(HustleEveryDayStrategies))
{
var x = new XmlSerializer(typeof(List<HustleEveryDayStrategyProperties>));
result = (List<HustleEveryDayStrategyProperties>)x.Deserialize(reader);
}
}
catch (Exception ex)
{
this.AddErrorLog("Ошибка загрузки {0}: {1}", HustleEveryDayStrategies, ex.Message);
}
}
return result;
}
public void SaveTestingHustleEveryDayStrategyProperties(List<HustleEveryDayStrategyTestingProperties> properties)
{
this.AddInfoLog("Сохранение тестовых стратегий в {0}", TestingHustleEveryDayStrategies);
using (var writer = new StreamWriter(TestingHustleEveryDayStrategies, false))
{
var mySerializer = new XmlSerializer(typeof(List<HustleEveryDayStrategyTestingProperties>));
mySerializer.Serialize(writer, properties);
}
}
public List<HustleEveryDayStrategyTestingProperties> LoadTestingHustleEveryDayStrategyProperties()
{
this.AddInfoLog("Загрузка стратегий тестирования из {0}", TestingHustleEveryDayStrategies);
var result = new List<HustleEveryDayStrategyTestingProperties>();
if (File.Exists(TestingStrategiesXml))
{
using (var reader = new StreamReader(TestingHustleEveryDayStrategies))
{
var x = new XmlSerializer(typeof(List<HustleEveryDayStrategyTestingProperties>));
result = (List<HustleEveryDayStrategyTestingProperties>)x.Deserialize(reader);
}
}
return result;
}
Идем в Main.
Добавляем маленький костыль.
private List<HustleEveryDayStrategy> _hustleEveryDayStrategies = new List<HustleEveryDayStrategy>();
private List<HustleEveryDayStrategy> _hustleEveryDayTestingStrategies = new List<HustleEveryDayStrategy>();
И почти как под копирку методы для добавления стратегий:
private void AddHustleEveryDayStrategy()
{
var properties = new HustleEveryDayStrategyProperties
{
// TODO: check if the stategy with same does exist
Name = "Новая стратегия {0}".Put(_newStrategyCount++),
};
AddHustleEveryDayStrategy(properties);
SaveStrategies();
}
private void AddHustleEveryDayStrategy(HustleEveryDayStrategyProperties properties)
{
var strategy = new HustleEveryDayStrategy
{
Params = properties,
Trader = ConnectionEngine.Instance.Trader
};
_logManager.Sources.Add(strategy);
var doc = new LayoutDocument
{
Title = strategy.Params.Name,
Content = new StrategyDocument
{
Strategy = strategy
},
CanClose = false
};
strategy.Params.PropertyChanged += (s, a) =>
{
if (a.PropertyName == "Name")
{
doc.Title = strategy.Params.Name;
}
SaveStrategies();
};
_documents.Add(strategy, doc);
_hustleEveryDayStrategies.Add(strategy);
this.AddInfoLog("Добавлена стратегия '{0}'", strategy.Name);
StrategiesDocumentPane.Children.Add(doc);
}
private void AddHustleEverydayTestingStrategy()
{
var properties = new HustleEveryDayStrategyTestingProperties
{
Name = "Тестирование {0}".Put(_newTestingCount++)
};
AddTestingStrategy(properties);
SaveTestingStrategies();
}
private void AddHustleEverydayTestingStrategy(HustleEveryDayStrategyTestingProperties properties)
{
var strategy = new HustleEveryDayStrategy
{
Params = properties,
Trader = ConnectionEngine.Instance.Trader
};
var doc = new LayoutDocument()
{
Title = strategy.Params.Name,
Content = new TestingDocument
{
Strategy = strategy
},
CanClose = false
};
strategy.Params.PropertyChanged += (s, a) =>
{
if (a.PropertyName == "Name")
{
doc.Title = strategy.Params.Name;
}
SaveTestingStrategies();
};
_testingDocuments.Add(strategy, doc);
_hustleEveryDayTestingStrategies.Add(strategy);
this.AddInfoLog("Добавлена тестовая стратегия '{0}'", strategy.Name);
StrategiesDocumentPane.Children.Add(doc);
}
Нужно добавить в InitializeConfiguration() - методе восстановления из настроек.
var hustleProperties = SettingsEngine.Instance.LoadHustleEveryDayStrategiesProperties();
foreach (var property in hustleProperties)
{
AddHustleEveryDayStrategy(property);
}
var testingHustleProperties = SettingsEngine.Instance.LoadTestingHustleEveryDayStrategyProperties();
foreach (var properties in testingHustleProperties)
{
AddTestingStrategy(properties);
}
Ну вот. Теперь сохранение настроек стратегий будет работать не правильно, а удаление будет удалять только из интерфейса, а при перезапуске все будет по-прежнему. И это только на первый взгляд.
Как починить это, а также о том, как добавить кнопки добавления стратегии в интерфейс, узнаем в следующей подчасти части 3.