using StockSharp.Quik;
namespace SampleRealTimeTesting
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using Ecng.Collections;
using Ecng.Common;
using Ecng.ComponentModel;
using Ecng.Xaml;
using StockSharp.Algo;
using StockSharp.Algo.Candles;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Indicators.Trend;
using StockSharp.Algo.Reporting;
using StockSharp.Algo.Testing;
using StockSharp.BusinessEntities;
using StockSharp.Logging;
using StockSharp.Messages;
using StockSharp.Xaml.Charting;
public partial class MainWindow
{
private bool _isConnected;
private readonly TimeSpan _timeFrame = TimeSpan.FromMinutes(5);
private readonly SynchronizedList<TimeFrameCandle> _historyCandles = new SynchronizedList<TimeFrameCandle>();
private CandleManager _candleManager;
private RealTimeEmulationTrader<QuikTrader> _trader;
private SmaStrategy _strategy;
private DateTime _lastHistoryCandle;
private Security _lkoh;
private readonly ChartArea _area;
private ChartCandleElement _candlesElem;
private ChartIndicatorElement _longMaElem;
private ChartIndicatorElement _shortMaElem;
public MainWindow()
{
InitializeComponent();
_area = new ChartArea();
_chart.Areas.Add(_area);
}
protected override void OnClosing(CancelEventArgs e)
{
if (_trader != null)
_trader.Dispose();
base.OnClosing(e);
}
private void ConnectClick(object sender, RoutedEventArgs e)
{
if (!_isConnected)
{
if (_trader == null)
{
//if (Login.Text.IsEmpty())
//{
// MessageBox.Show(this, "Не указан логин.");
// return;
//}
//else if (Password.Password.IsEmpty())
//{
// MessageBox.Show(this, "Не указан пароль.");
// return;
//}
// тестовый портфель
var portfolio = new Portfolio
{
Name = "test account",
BeginValue = 1000000,
};
// создаем подключение
_trader = new RealTimeEmulationTrader<QuikTrader>(new QuikTrader
(@"C:\Users\nryabkov\Documents\QUIK NetTrader\info.exe"));
var logManager = new LogManager();
logManager.MaxMessageCount = -1; // без этого будет буферизация логов и они будут неактуальны при остановке в дебаггере.
logManager.Listeners.Add(new FileLogListener("sample.log"));
logManager.Sources.Add(_trader);
// очищаем из текстового поля в целях безопасности
Password.Clear();
// подписываемся на событие успешного соединения
_trader.Connected += () =>
{
// возводим флаг, что соединение установлено
_isConnected = true;
// разблокируем кнопку Экспорт
this.GuiAsync(() => ChangeConnectStatus(true));
// передаем первоначальное значение размера портфеля в эмулятор
_trader.TransactionAdapter.SendInMessage(portfolio.ToMessage());
_trader.TransactionAdapter.SendInMessage(new PortfolioChangeMessage
{
PortfolioName = portfolio.Name
}.Add(PositionChangeTypes.BeginValue, portfolio.BeginValue));
_candleManager = new CandleManager(_trader);
//_trader.UnderlyingConnector.NewCandles += (series, candles) => _historyCandles.SyncDo(col =>
//{
// _historyCandles.AddRange(candles.Cast<TimeFrameCandle>());
// this.GuiAsync(() =>
// {
// foreach (var candle in candles)
// ProcessCandle(candle);
// });
//});
_trader.NewSecurities += securities => this.GuiAsync(() =>
{
// находим нужную бумагу
var lkoh = securities.FirstOrDefault(s => s.Code == "LKOH");
if (lkoh != null)
{
_lkoh = lkoh;
this.GuiAsync(() =>
{
Start.IsEnabled = true;
});
}
});
_trader.NewMyTrades += trades => this.GuiAsync(() =>
{
if (_strategy != null)
{
// найти те сделки, которые совершила стратегия скользящей средней
trades = trades.Where(t => _strategy.Orders.Any(o => o == t.Order));
_trades.Trades.AddRange(trades);
}
});
// подписываемся на событие о неудачной регистрации заявок
_trader.OrdersRegisterFailed += OrdersFailed;
_candleManager.Processing += (s, candle) =>
{
// выводим только те свечки, которые не были отрисованы как исторические
if (candle.OpenTime > _lastHistoryCandle)
ProcessCandle(candle);
};
_trader.StartExport();
this.GuiAsync(() =>
{
ConnectBtn.IsEnabled = false;
});
};
// подписываемся на событие разрыва соединения
_trader.ConnectionError += error => this.GuiAsync(() =>
{
// заблокируем кнопку Экспорт (так как соединение было потеряно)
ChangeConnectStatus(false);
MessageBox.Show(this, error.ToString(), "Ошибка соединения");
});
_trader.ProcessDataError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), "Ошибка обработки данных"));
}
_trader.Connect();
}
else
{
_trader.Disconnect();
}
}
private void OrdersFailed(IEnumerable<OrderFail> fails)
{
this.GuiAsync(() =>
{
foreach (var fail in fails)
MessageBox.Show(this, fail.Error.ToString(), "Ошибка регистрации заявки");
});
}
private void ChangeConnectStatus(bool isConnected)
{
_isConnected = isConnected;
ConnectBtn.Content = isConnected ? "Отключиться" : "Подключиться";
}
private void OnLog(LogMessage message)
{
// если стратегия вывела не просто сообщение, то вывести на экран.
if (message.Level != LogLevels.Info && message.Level != LogLevels.Debug)
this.GuiAsync(() => MessageBox.Show(this, message.Message));
}
private void OnStrategyPropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.GuiAsync(() =>
{
Status.Content = _strategy.ProcessState;
PnL.Content = _strategy.PnL;
Slippage.Content = _strategy.Slippage;
Position.Content = _strategy.Position;
Latency.Content = _strategy.Latency;
});
}
private void StartClick(object sender, RoutedEventArgs e)
{
// если были получены и инструмент, и портфель
if (_strategy == null)
{
// создаем скользящие средние, на 80 5-минуток и 10 5-минуток
var longSma = new SimpleMovingAverage { Length = 80 };
var shortSma = new SimpleMovingAverage { Length = 10 };
// регистрируем наш тайм-фрейм
var series = new CandleSeries(typeof(TimeFrameCandle), _lkoh, _timeFrame);
// создаем торговую стратегию
_strategy = new SmaStrategy(series, longSma, shortSma)
{
Volume = 1,
Security = _lkoh,
Portfolio = _trader.Portfolios.First(),
Connector = _trader,
};
_strategy.Log += OnLog;
_strategy.PropertyChanged += OnStrategyPropertyChanged;
_candlesElem = new ChartCandleElement();
_area.Elements.Add(_candlesElem);
_longMaElem = new ChartIndicatorElement
{
Title = "Длинная",
Indicator = _strategy.LongSma,
};
_area.Elements.Add(_longMaElem);
_shortMaElem = new ChartIndicatorElement
{
Title = "Короткая",
Indicator = _strategy.ShortSma,
};
_area.Elements.Add(_shortMaElem);
// начинаем получать текущие сделки (для построения свечек реального времени)
_trader.RegisterTrades(_lkoh);
//// делаем запрос в SmartCOM для получения исторических данных по 5-минуткам для Лукойла за период в 5 дней
//_trader.UnderlyingConnector.RequestCandles(_lkoh, SmartComTimeFrames.Minute5,
// new Range<DateTime>(DateTime.Today - TimeSpan.FromDays(5), _lkoh.GetMarketTime()));
_lastHistoryCandle = _timeFrame.GetCandleBounds(_lkoh).Min;
Report.IsEnabled = true;
}
if (_strategy.ProcessState == ProcessStates.Stopped)
{
// запускаем процесс получения стакана, необходимый для работы алгоритма котирования
_trader.RegisterMarketDepth(_strategy.Security);
_strategy.Start();
Start.Content = "Стоп";
}
else
{
_trader.UnRegisterMarketDepth(_strategy.Security);
_strategy.Stop();
Start.Content = "Старт";
}
}
private void ProcessCandle(Candle candle)
{
var longValue = candle.State == CandleStates.Finished ? new ChartIndicatorValue(_strategy.LongSma, _strategy.LongSma.Process(candle)) : null;
var shortValue = candle.State == CandleStates.Finished ? new ChartIndicatorValue(_strategy.ShortSma, _strategy.ShortSma.Process(candle)) : null;
_chart.ProcessValues(candle.OpenTime, new Dictionary<IChartElement, object>
{
{ _candlesElem, candle },
{ _longMaElem, longValue },
{ _shortMaElem, shortValue },
});
}
private void ReportClick(object sender, RoutedEventArgs e)
{
// сгерерировать отчет по прошедшему тестированию
new ExcelStrategyReport(_strategy, "sma.xls").Generate();
// открыть отчет
Process.Start("sma.xls");
}
}
}