Доброго всем дня, особенно Михаилу :). Начал осваивать событийный подход, забуксовал.
Подскажите, пожалуйста, как правильно запускать стратегию наподобие той, что приведена в примере (class MyOwnStrategy : ActionStrategy)? Нужно ли добавлять в нее конструктор и отдельно передавать Security?
Сейчас запускаю на ФОРТС так:
_strategy = new MyOwnStrategy() { Volume = 1 };
_manager.Register(_strategy, this.Portfolios.SelectedPortfolio, _rts);
if (_strategy.ProcessState == StrategyProcessStates.Stopped)
{
_strategy.Start();
}
else
{
_strategy.Stop();
}
Стратегия нормально запускается и останавливается из GUI примера SampleSMA, лог пишется, но сделок не происходит на любом таймфрейме.
Лог обычно такой: MOS 20:34:52.0212958 Стратегия запущена. MOS 20:36:11.3213772 Стратегия останавливается. MOS 20:36:11.6273947 Стратегия остановлена.
Событийную стратегию взял из мануала, без изменений, версия 3.0. Буду признателен за помощь.
Весь запускающий код, кроме самой стратегии из примера:
namespace SampleSMA
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using MessageBox = System.Windows.MessageBox;
using AmCharts.Windows.Stock;
using Ecng.Collections;
using Ecng.Common;
using Ecng.ComponentModel;
using Ecng.Trading.Algo;
using Ecng.Trading.Algo.Candles;
using Ecng.Trading.Algo.Logging;
using Ecng.Trading.Algo.Reporting;
using Ecng.Trading.Algo.Strategies;
using Ecng.Trading.BusinessEntities;
using Ecng.Trading.Quik;
using Ecng.Trading.Xaml;
using Ecng.Xaml;
public partial class MainWindow
{
private readonly TimeSpan _timeFrame = TimeSpan.FromMinutes(1);
private QuikTrader _trader;
private MyOwnStrategy _strategy;
private RealTimeStrategyManager _manager;
private bool _isDdeStarted;
private Security _rts;
public CandleManager _candleManager;
public MainWindow()
{
InitializeComponent();
// изменяет текущий формат, чтобы нецелое числа интерпритировалось как разделенное точкой.
var cci = new CultureInfo(Thread.CurrentThread.CurrentCulture.Name) { NumberFormat = { NumberDecimalSeparator = "." } };
Thread.CurrentThread.CurrentCulture = cci;
}
private void _orders_OrderSelected(object sender, EventArgs e)
{
this.CancelOrders.IsEnabled = _orders.SelectedOrders.Count() > 0;
}
protected override void OnClosing(CancelEventArgs e)
{
if (_trader != null)
{
_manager.Dispose();
if (_isDdeStarted)
StopDde();
_trader.Dispose();
}
base.OnClosing(e);
}
private void FindPath_Click(object sender, RoutedEventArgs e)
{
var dlg = new FolderBrowserDialog();
if (!this.Path.Text.IsEmpty())
dlg.SelectedPath = this.Path.Text;
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
this.Path.Text = dlg.SelectedPath;
}
}
private void Connect_Click(object sender, RoutedEventArgs e)
{
if (_trader == null || !_trader.IsConnected)
{
if (_trader == null)
{
if (this.Path.Text.IsEmpty())
{
MessageBox.Show(this, "Путь к Quik не выбран.");
return;
}
// создаем шлюз
_trader = new QuikTrader(this.Path.Text);
// создаем менеджер стратегий
_manager = new RealTimeStrategyManager(_trader);
this.Portfolios.Trader = _trader;
_trader.Connected += () =>
{
_candleManager = new CandleManager(_trader);
_trader.NewSecurities += securities => this.GuiAsync(() =>
{
// находим нужную бумагу
var rts = securities.FirstOrDefault(s => s.Code == "RIM1");
if (rts != null)
{
_rts = rts;
this.GuiAsync(() =>
{
this.Start.IsEnabled = true;
});
}
});
_trader.ConnectionError += ex =>
{
if (ex != null)
this.GuiAsync(() => MessageBox.Show(this, ex.ToString()));
};
this.GuiAsync(() =>
{
this.ConnectBtn.IsEnabled = false;
this.ExportDde.IsEnabled = true;
this.Report.IsEnabled = true;
});
};
}
_trader.Connect();
}
else
_trader.Disconnect();
}
private void OnNewOrder(Order order)
{
_orders.Orders.Add(order);
this.GuiAsync(() => _chart.Orders.Add(order));
}
private void OnLog(Strategy strategy, StrategyErrorStates errorState, string message)
{
// если стратегия вывела не просто сообщение, то вывести на экран.
if (errorState != StrategyErrorStates.None)
this.GuiAsync(() => MessageBox.Show(this, message));
}
private void OnStrategyPropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.GuiAsync(() =>
{
this.Status.Content = _strategy.ProcessState;
this.PnL.Content = _strategy.PnLManager.PnL;
this.Slippage.Content = _strategy.SlippageManager.Slippage;
this.Position.Content = _strategy.PositionManager.Position;
this.Latency.Content = _strategy.LatencyManager.Latency;
});
}
private void StartDde()
{
_trader.StartExport();
_isDdeStarted = true;
}
private void StopDde()
{
_trader.StopExport();
_isDdeStarted = false;
}
private void ExportDde_Click(object sender, RoutedEventArgs e)
{
if (_isDdeStarted)
StopDde();
else
StartDde();
}
private void CancelOrders_Click(object sender, RoutedEventArgs e)
{
_orders.SelectedOrders.ForEach(_trader.CancelOrder);
}
private void Start_Click(object sender, RoutedEventArgs e)
{
if (_strategy == null)
{
if (this.Portfolios.SelectedPortfolio == null)
{
MessageBox.Show(this, "Портфель не выбран.");
return;
}
// создаем стратегию
_strategy = new MyOwnStrategy() { Volume = 1 };
_strategy.Log += OnLog;
_strategy.NewOrder += OnNewOrder;
_strategy.PropertyChanged += OnStrategyPropertyChanged;
// регистрируем стратегию, чтобы она начала обрабатываться
_manager.Register(_strategy, this.Portfolios.SelectedPortfolio, _rts);
var fileLogger = new FileStrategyLogger("{0}_{1:00}_{2:00}.txt".Put(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day));
fileLogger.Strategies.Add(_strategy);
this.Report.IsEnabled = true;
}
if (_strategy.ProcessState == StrategyProcessStates.Stopped)
{
_strategy.Start();
this.Start.Content = "Хватит";
}
else
{
_strategy.Stop();
this.Start.Content = "Понеслась";
}
}
private void Report_Click(object sender, RoutedEventArgs e)
{
var fileName = "report_{0}_{1}.xls".Put(_strategy.Security.Code, DateTime.Now.ToString("yyyy_MM_dd_HH_mm"));
new ExcelStrategyReport(_strategy, System.IO.Path.Combine(Directory.GetCurrentDirectory(), fileName)).Generate();
}
}
}
Comentarios (14)
Iniciar sesión o Crear cuenta, Inicie sesión o regístrese para dejar un comentario
Точка останова, дебаггер и вперед.🙂
Спасибо, буду ковыряться.
Попробовал и с конструктором, и без - говорит, что не может получить значение _candleBounds. Хотя _candleManager на месте, и на остальные поля не ругается. Вот такой неуспех.
Потому что там лямбда выражение стоит. Прочитайте, как эта вещь работает. И бряку ставьте во внутрь.
Ай, сильно не хотелось в лямбды лезть, теперь придется. Спасибо, пойду подтягивать матчасть.
Чтобы не плодить сущности напишу здесь ) Есть ли вообще возможность запускать очередную итерацию стратегии не периодически, а именно по событию? Хотелось бы воспользоваться преимуществами оформления кода с виде Strategy, но не очень нравится исполнение по времени.
PS Только начал разбираться, извините, если что пропустил.
Не итерацию, а действие. Так же, как и выше написал, через событийную модель.
Через ActionStrategy и добавления событий... Вопрос уже содержит ответ. Или я видимо что-то не понимаю в вопросе, или вы не до конца мысль расписываете. Как предложение, попробуйте написать практический пример с событиями.
Большое спасибо за ответ!
Вопрос как\где контролируется с какой периодичностью (и сколько раз?) будет выполняться действие?
Дело в том, что нужно, чтобы условия проверялись не периодически, а по событию. Как это сделать?
Если просто MakePeriodica(), то бесконечно. Если через перегруженный метод http://stocksharp.com/doc/help/html/O_T_Ecng_Trading_Algo_Strategies_ActionRule_MakePeriodical.htm Через то можно указывать критерий.
Мы опять вернулись к началу. Нужно использовать событийную модель. Как это сделать я показал в документации.
Проблема, для меня по крайней мере, в том, что в документации фрагменты кода, а работающего примера нет. Спасибо за ответы!
У вас как с языком C#? Событийная модель построена на делегатах, Action и Func. Прочитайте что это такое и как используется. Я подозреваю, что вы просто подошли к задаче не с того конца.
Все-таки было бы очень желательно, чтобы такие ключевые вещи имели более подробные объяснения (см. например http://stocksharp.com/forum/1287/ и http://stocksharp.com/forum/1214/ActionStrategy-chastota-provierki-1-siek/ ) и рабочие примеры с разнообразными вариантами применения. А уж с какой целью "делать событие периодичным" ( http://stocksharp.com/doc/help/html/8c0327db-494a-4fe0-aba8-0d4b93dea60e.htm ) и что и как конкретно делает MakePeriodical (про собственно период до сих пор ничего не известно 🙂) из описания малопонятно. Я подозреваю, что там все просто и логично, но из документации это сразу понять для начинающего все-таки сложновато (не претендую на суперсообразительность 🙂).
UPD Еще добавлю для ясности: я не использую импорт из таблицы всех сделок и CandleManager для формирования свечей. И вот эти два замечания несколько меня дезориентировали: