Создание роботов с помощью S#. Часть 3. Реализация интерфейсов~/topic/357/sozdanie-robotov-s-pomoshshyu-s_-chast-3_-realizatsiya-interfeisov/Copyright @ StockSharp Platform LLC 2010 - 20242024-03-28T16:21:01Zhttps://stocksharp.ru/images/logo.pnghttps://stocksharp.ru/posts/m/23155/ public override LogLevels LogLevel { get { return LogLevels.Debug; } set { } } по вкусу :) Если это...2012-12-21T14:28:26Z2012-12-21T14:44:00ZГеннадий Ванин (Gennady Vanin)https://stocksharp.ru/users/6413/info@stocksharp.ru<div class="quote"><span class="quotetitle">VassilSanych <a href="https://stocksharp.ru/posts/m/23154/"><img src="https://stocksharp.ru/images/icon_latest_reply.gif" title="Перейти" alt="Перейти" /></a></span><div class="innerquote"><br /><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
public override LogLevels LogLevel
{
get { return LogLevels.Debug; }
set { }
} </pre>
</div></div> <br />по вкусу :)</div></div><br />Если этого альтруиста не забанить, то, тогда, прийдётся менять бизнес-модель с бесплатного коммерческого продукта на платный некоммерческий продукт<br /><br />Т.е., вместо того, чтобы пытаться продавать техподдержку и обучение того, чем нельзя пользоватьсяновичкам (и, соответственно, не находит широкого использования) на продажу небесплатного продукта с бесплатной техподдержкой-обучением-раскруткой , которым все легко пользуются и с более широким вовлечением волонтеров-разработчиков.<br /><br />VassilSanych - коварный и лукавый волонтёр-разработчик, который хочет <b>бесплатно</b> поучаствовать в развитии проекта StockSharp, поломав давно установившийся и отлаженный статус-кво!Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/23154/Смотрю, многие, в том числе и я, пользовались приведённым кодом, как основой. У многих в цитируемом ...2012-12-21T13:00:54Z2012-12-21T13:00:54ZVassilSanychhttps://stocksharp.ru/users/6491/info@stocksharp.ruСмотрю, многие, в том числе и я, пользовались приведённым кодом, как основой. У многих в цитируемом тексте присутствует WriteLog :) <br />Небольшое замечание: для подключения источника логирования не нужно реализовывать ILogSource.<br />Достаточно унаследоваться от BaseLogReceiver<ВашКласс> и тогда можно замечательно использовать метод AddLog, и методы предоставляемые для него классом LoggingHelper: AddErrorLog, AddInfoLog и т.п.<br />Правда для полного логирования необходимо добавить ещё<br /><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
public override LogLevels LogLevel
{
get { return LogLevels.Debug; }
set { }
} </pre>
</div></div> <br />по вкусу :)Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/135/Теперь приступим к реализации интерфейсов из 2 части статьи “Создание роботов с помощью S#. Часть 2....2012-03-18T21:58:56Z2012-12-17T15:06:55ZFinDirectorhttps://stocksharp.ru/users/473/info@stocksharp.ruТеперь приступим к реализации интерфейсов из 2 части статьи “Создание роботов с помощью S#. Часть 2. Базовый класс для всех стратегий”. Здесь западные специалисты рекомендуют вначале реализовывать тестовые версии интерфейсов. И писать сразу UNIT-тесты. Смотрите пример SampleEmulationTesting из библиотеки S#. Но ведь программист — это высшая форма существования разума во Вселенной, и поэтому, в принципе не может ошибаться. Сразу в бой!<br /><br /><b>QuikTraderBuilder</b><br />Реализуем создание торговой системы Quik. Основной метод:<br /><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
public ITrader BuildTrader()</pre>
</div></div><br />Нужно учитывать, что метод могут одновременно вызвать из разных потоков и создавать только 1 Quik.<br /><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
public sealed class QuikTraderBuilder : ITraderBuilder, ILogSource
{
private object lockObject = new object();
private Task task;
private bool isConnected;
public string Path { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public string DdeServer { get; set; }
public string DllName { get; set; }
private string title;
public string Title
{
get { return title ?? Login; }
set { title = value; }
}
public ITrader Trader { get; private set; }
public ICandleManager CandleManager { get; private set; }
public event Action IsConnectedChanged;
public ITrader BuildTrader()
{
lock (lockObject)
{
if (task == null)
task = Task.Factory.StartNew(CreateTrader);
}
task.Wait();
return Trader;
}
private void CreateTrader()
{
QuikTerminal terminal = RunTerminalInternal();
QuikTrader quikTrader;
WriteLog(ErrorTypes.None, "Создаем шлюз взаимодействия с системой Quik.");
if (!string.IsNullOrEmpty(DdeServer))
{
if (!string.IsNullOrEmpty(DllName))
quikTrader = new QuikTrader(terminal.DirectoryName, DdeServer, DllName);
else
quikTrader = new QuikTrader(terminal.DirectoryName, DdeServer);
}
else
{
quikTrader = new QuikTrader(terminal.DirectoryName);
}
quikTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MarginBuy);
quikTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MinPrice);
quikTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MaxPrice);
quikTrader.ReConnectionSettings.Interval = TimeSpan.FromSeconds(10);
quikTrader.ReConnectionSettings.WorkingTime = Exchange.Rts.WorkingTime;
quikTrader.Connected += () =>
{
UpdateIsConnected(null);
if (!quikTrader.IsExportRunning)
{
WriteLog(ErrorTypes.None, "Запускаем экспорт данных.");
quikTrader.StartExport();
Verify(quikTrader.Terminal);
}
};
quikTrader.ConnectionError += ex => UpdateIsConnected(ex);
quikTrader.Disconnected += () => UpdateIsConnected(null);
Trader = quikTrader;
CandleManager = new CandleManager(quikTrader);
WriteLog(ErrorTypes.None, "Производим подключение.");
quikTrader.Connect();
}
private void UpdateIsConnected(Exception ex)
{
var trader = Trader;
bool isConnectedNew = trader != null && trader.IsConnected;
if (isConnected != isConnectedNew)
{
isConnected = isConnectedNew;
WriteLog(ErrorTypes.None, isConnectedNew ? "Соединение подключено." : "Соединение отключено.");
RaiseIsConnectedChanged();
if (ex != null) WriteLog(ErrorTypes.Error, ex.Message);
}
}
private void RaiseIsConnectedChanged()
{
var handler = IsConnectedChanged;
if (handler != null) handler();
}
public void RunTerminal()
{
RunTerminalInternal();
}
private QuikTerminal RunTerminalInternal()
{
QuikTerminal terminal = QuikTerminal.Get(Path);
if (!terminal.IsLaunched)
terminal.Launch();
if (!terminal.IsConnected)
terminal.Login(Login, Password);
return terminal;
}
private void Verify(QuikTerminal terminal)
{
var errors = terminal.GetTableSettings();
foreach (var error in errors)
{
string message = string.Format("Таблица {0}. {1}", error.Table.Caption, error.Error.Message);
WriteLog(ErrorTypes.Warning, message);
}
}
public void Dispose()
{
if (task != null)
task.Dispose();
if (CandleManager != null)
CandleManager.Dispose();
if (Trader != null)
Trader.Dispose();
}
#region ILogSource
public Ecng.Collections.INotifyList<ILogSource> Childs
{
get { return null; }
}
private Guid id = Guid.NewGuid();
public Guid Id
{
get { return id; }
}
public event Action<LogMessage> Log;
public string Name
{
get { return Title; }
}
public ILogSource Parent
{
get { return null; }
}
private void RaiseLog(LogMessage logMessage)
{
var handler = Log;
if (handler != null)
handler(logMessage);
}
private void WriteLog(ErrorTypes errorType, string message)
{
LogMessage logMessage = new LogMessage(this, DateTime.Now, errorType, message);
RaiseLog(logMessage);
}
#endregion
}</pre>
</div></div><br /><br />Создание других торговых систем оставим читателю в качестве домашнего задания.<br /><br /><b>PortfolioSelector</b><br />Реализуем получение портфеля по его имени. Основной момент: ждем, когда будет инициализирована сумма на счете, т.к. она нужна для определения размера позиции.<br /><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
public class PortfolioSelector : IPortfolioSelector
{
private string title;
public string Title
{
get { return title ?? PortfolioName; }
set { title = value; }
}
public string PortfolioName { get; set; }
public Portfolio GetPortfolio(ITrader trader)
{
Portfolio result = FindPortfolio(trader);
if (result != null)
return result;
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
Action<IEnumerable<Portfolio>> onPortfoliosChanged = p =>
{
if (FindPortfolio(trader) != null)
manualResetEvent.Set();
};
trader.NewPortfolios += onPortfoliosChanged;
trader.PortfoliosChanged += onPortfoliosChanged;
manualResetEvent.WaitOne(TimeSpan.FromSeconds(30));
trader.NewPortfolios -= onPortfoliosChanged;
trader.PortfoliosChanged -= onPortfoliosChanged;
result = FindPortfolio(trader);
return result;
}
private Portfolio FindPortfolio(ITrader trader)
{
return trader.Portfolios.FirstOrDefault(p => p.Name == PortfolioName && p.BeginAmount.Value != 0);
}
}</pre>
</div></div><br /><b>SecuritySelector</b><br />Поиск инструмента по его коду. Реализация аналогична PortfolioSelector.<br /><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
public class SecuritySelector : ISecuritySelector
{
private string title;
public string Title
{
get { return title ?? SecurityCode; }
set { title = value; }
}
public string SecurityCode { get; set; }
public Security GetSecurity(ITrader trader)
{
Security result = FindSecurity(trader);
if (result != null)
return result;
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
Action<IEnumerable<Security>> onNewSecurities = s =>
{
if (FindSecurity(trader) != null)
manualResetEvent.Set();
};
trader.NewSecurities += onNewSecurities;
manualResetEvent.WaitOne(TimeSpan.FromSeconds(30));
trader.NewSecurities -= onNewSecurities;
result = FindSecurity(trader);
return result;
}
private Security FindSecurity(ITrader trader)
{
return trader.Securities.FirstOrDefault(s => s.Code == SecurityCode);
}
}</pre>
</div></div><br /><b>MarginVolumeSizer</b><br />Определение размера позиции по лимиту открытых позиций и гарантийному обеспечению.<br /><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
public class MarginVolumeSizer : IVolumeSizer
{
public double Ratio { get; set; }
public decimal MaxCapital { get; set; }
public MarginVolumeSizer()
{
MaxCapital = decimal.MaxValue;
}
public int GetVolume(Portfolio portfolio, Security security)
{
decimal capital = Math.Min(portfolio.BeginAmount.Value, MaxCapital);
int quantity = (int)(capital * (decimal)Ratio / security.MarginBuy);
return quantity;
}
}</pre>
</div></div><br /><b>RegistrySettingsProvider</b><br />Чтение и запись состояния стратегии из реестра.<br /><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
public class RegistrySettingsProvider : ISettingsProvider
{
public string SubKey { get; set; }
public RegistrySettingsProvider()
{
SubKey = @"Software\FinDirector";
}
public string ReadSetting(string name)
{
using (RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(SubKey))
{
return (string)registryKey.GetValue(name);
}
}
public void WriteSetting(string name, string value)
{
using (RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(SubKey))
{
registryKey.SetValue(name, value);
}
}
}</pre>
</div></div><br /><b>FinamHistoryCandleProvider</b><br />Получение исторических свечей с сайта финама. Реализацию не выкладываю, т.к. много кода.<br /><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
public class FinamHistoryCandleProvider : IHistoryCandleProvider
{
public int FinamSecurityCode { get; set; }
public TimeSpan TimeFrame { get; set; }
public FinamHistoryCandleProvider()
{
FinamSecurityCode = 17455;
TimeFrame = TimeSpan.FromHours(1);
}
public List<TimeFrameCandle> GetHistoryCandles(DateTime beginDate, DateTime endDate)
{
…
}</pre>
</div></div><br /><br /><span style="font-size:120%"><div align="right"><b>Автор статьи — Вадим Чижов</b></div></span>Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/22770/Даже не знаю в чем точто была проблема но все заработало. FinDirector, с вашего позволения могу выло...2012-12-02T15:01:37Z2012-12-02T15:01:37Zserebryakov_ahttps://stocksharp.ru/users/28627/info@stocksharp.ru<div class="quote"><span class="quotetitle">Serg <a href="https://stocksharp.ru/posts/m/21560/"><img src="https://stocksharp.ru/images/icon_latest_reply.gif" title="Перейти" alt="Перейти" /></a></span><div class="innerquote">Даже не знаю в чем точто была проблема но все заработало. <br /><b>FinDirector</b>, с вашего позволения могу выложить проект-шаблон целиком.</div></div><br /><br />Добрый день! Попытался реализовать описанный выше каркас - появились ошибки реализации интерфейсов(ITraderBuilder, ILogSource). версия библиотеки 4.1.6. Можете ли вы поделиться реализацией проекта-шаблона или подсказать в чем там были траблы? Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/22705/ FinamSecurityCode = 17455; Пока, я просто выбираю руками нужный инструмент и слушаю tcpmon'ом запро...2012-11-28T13:51:18Z2012-11-28T13:51:18ZDenhttps://stocksharp.ru/users/6003/info@stocksharp.ru<div class="quote"><span class="quotetitle">FinDirector <a href="https://stocksharp.ru/posts/m/22618/"><img src="https://stocksharp.ru/images/icon_latest_reply.gif" title="Перейти" alt="Перейти" /></a></span><div class="innerquote"><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
FinamSecurityCode = 17455;
</pre>
</div></div></div></div><br /><br />Пока, я просто выбираю руками нужный инструмент и слушаю tcpmon'ом запрос браузра и оттуда достаю код.<br /><br />Подскажите, пожалуйста, как получить список всех доступных кодов инструментов?<br />Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/22625/Огромное спасибо! 2012-11-21T18:19:19Z2012-11-21T18:19:19ZGunn7https://stocksharp.ru/users/27628/info@stocksharp.ruОгромное спасибо! Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/22618/ using System; using System.Collections.Generic; using System.ComponentModel; using System.Globaliza...2012-11-20T12:41:24Z2012-11-20T12:41:24ZFinDirectorhttps://stocksharp.ru/users/473/info@stocksharp.ru<div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Net;
using FinDirector.Infrastructure;
namespace FinDirector.Modules.SharedServices
{
public class FinamHistoryCandleProvider : IHistoryCandleProvider
{
public int FinamSecurityCode { get; set; }
[Description("Таймфрейм.")]
public TimeSpan TimeFrame { get; set; }
public FinamHistoryCandleProvider()
{
FinamSecurityCode = 17455;
TimeFrame = TimeSpan.FromHours(1);
}
public IList<Candle> GetHistoryCandles(DateTime beginDate, DateTime endDate)
{
string uri = GetInstrumentUrl(beginDate, endDate);
WebRequest request = WebRequest.Create(uri);
using (StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream()))
{
IList<Candle> result = new CandleReader().ReadCandles(sr);
return result;
}
}
private int GetPeriodCode()
{
int period = 3;
if (TimeFrame == TimeSpan.FromMinutes(5))
period = 3;
else if (TimeFrame == TimeSpan.FromHours(1))
period = 7;
else if (TimeFrame == TimeSpan.FromDays(1))
period = 8;
return period;
}
private string GetInstrumentUrl(DateTime beginDate, DateTime endDate)
{
int period = GetPeriodCode();
string Ticker = "data";
string fileName = Ticker + ".txt";
string url = string.Format(CultureInfo.InvariantCulture,
"http://195.128.78.52/{0}?d=d&market=14&em={8}&df={2}&mf={3}&yf={4}&dt={5}&mt={6}&yt={7}&p={9}&f={0}&e=.txt&cn={1}&dtf=1&tmf=1&MSOR=0&sep=1&sep2=1&datf=1&at=1",
fileName, Ticker,
beginDate.Day, beginDate.Month - 1, beginDate.Year,
endDate.Day, endDate.Month - 1, endDate.Year,
FinamSecurityCode, period);
return url;
}
}
}
class CandleReader
{
private bool SkipFirstLine = true;
private char Separator = ',';
public IList<Candle> ReadCandles(StreamReader sr)
{
List<Candle> result = new List<Candle>();
if (SkipFirstLine)
{
sr.ReadLine();
}
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
string[] values = line.Split(new char[] { Separator });
Candle candle = ReadCandle(values);
result.Add(candle);
}
return result;
}
private Candle ReadCandle(string[] line)
{
int dateIndex = 2;
int timeIndex = 3;
int openIndex = 4;
int highIndex = 5;
int lowIndex = 6;
int closeIndex = 7;
int date = Int32.Parse(line[dateIndex], CultureInfo.InvariantCulture);
int time = Int32.Parse(line[timeIndex], CultureInfo.InvariantCulture);
var result = new Candle()
{
DateTime = new DateTime(date / 10000, (date / 100) % 100, date % 100,
time / 10000, (time / 100) % 100, 0),
OpenPrice = double.Parse(line[openIndex], CultureInfo.InvariantCulture),
ClosePrice = double.Parse(line[closeIndex], CultureInfo.InvariantCulture),
HighPrice = double.Parse(line[highIndex], CultureInfo.InvariantCulture),
LowPrice = double.Parse(line[lowIndex], CultureInfo.InvariantCulture)
};
return result;
}
}
</pre>
</div></div>Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/22008/Присоединяюсь к serq, спасибо за статьи. Может все же выложите реализацию получения свечей с финама....2012-10-24T20:09:44Z2012-10-24T20:09:44ZGunn7https://stocksharp.ru/users/27628/info@stocksharp.ruПрисоединяюсь к serq, спасибо за статьи.<br />Может все же выложите реализацию получения свечей с финама. Повис на этом уже который день...<br /><br />Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/21560/Даже не знаю в чем точто была проблема но все заработало. FinDirector, с вашего позволения могу выло...2012-09-27T13:53:42Z2012-09-27T13:53:42ZSerghttps://stocksharp.ru/users/484/info@stocksharp.ruДаже не знаю в чем точто была проблема но все заработало. <br /><b>FinDirector</b>, с вашего позволения могу выложить проект-шаблон целиком.Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/21552/Тоже использую 4.0.23. Все работает. Могу только посоветовать создать новый пустой проект и наладить...2012-09-27T11:04:35Z2012-09-27T11:04:35ZFinDirectorhttps://stocksharp.ru/users/473/info@stocksharp.ruТоже использую 4.0.23. Все работает. Могу только посоветовать создать новый пустой проект и наладить в нем логи, и в уже имеющемся проекте отключить логи. Тогда и разберетесь, что именно и почему не работает.Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/21549/LogManager.Listeners.Add(new GuiLogListener(_monitor)); Да я вроде так и делаю но почемуто все вообщ...2012-09-27T09:20:20Z2012-09-27T09:42:01ZSerghttps://stocksharp.ru/users/484/info@stocksharp.ru<div class="quote"><span class="quotetitle">FinDirector <a href="https://stocksharp.ru/posts/m/21540/"><img src="https://stocksharp.ru/images/icon_latest_reply.gif" title="Перейти" alt="Перейти" /></a></span><div class="innerquote"><div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
LogManager.Listeners.Add(new GuiLogListener(_monitor));</pre>
</div></div></div></div><br /><br />Да я вроде так и делаю но почемуто все вообще виснет. Может проблема в версии 4.0.23? Вы какую версию используете? <br /><br />ps: да и в логфайл сообщения от трейдера также не попадают( Мне кажется что гуи синхронизация здесь непричем. Скорее проблема с реализацией ILogSourse. Хотя могу только догадыватся так как не профи)<br />FinDirector, подскажите, у вас то все работает или всетаки чтото меняли после публикации своих статей?Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/21540/LogManager.Listeners.Add(new GuiLogListener(_monitor));2012-09-27T06:02:29Z2012-09-27T06:02:29ZFinDirectorhttps://stocksharp.ru/users/473/info@stocksharp.ru<div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
LogManager.Listeners.Add(new GuiLogListener(_monitor));</pre>
</div></div>Copyright @ StockSharp Platform LLC 2010 - 2024https://stocksharp.ru/posts/m/21534/Спасибо за статьи) Пытаюсь разбираться. Завис на реализации QuikTraderBuilder. Никак не разберусь по...2012-09-26T21:19:25Z2012-09-26T21:19:58ZSerghttps://stocksharp.ru/users/484/info@stocksharp.ruСпасибо за статьи) <br />Пытаюсь разбираться. Завис на реализации QuikTraderBuilder. Никак не разберусь почему монитор не получает сообщения от QuikTraderBuilder, видимо что-то с реализацией ILogSource.<br /> <div class="code"><strong>Код</strong><div class="innercode"><pre class="brush:csharp">
private void RaiseLog(LogMessage logMessage)
{
var handler = Log;
if (handler != null)
handler(logMessage); <<-- здесь возникает ошибка Current thread is not a GUI.
}</pre>
</div></div><br /><br />Буду рад помощи)Copyright @ StockSharp Platform LLC 2010 - 2024