Проверил на SampleHistoryTesting. Минимально подпаравив.
Получается тоже самое. Как сделать чтоб время свечек и сделок совпадали, и сделки правильно отображались на графике?
SS_SPFB.RTS@RTS_test account | 19.12.2012 19:00:00.000 | | Стратегия запущена. [0,-1]. Позиция при старте 0.
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:05:00.000 | | Новая свеча 20.12.2012 10:00:00: 151030,00000;151060,00000;150670,00000;150730,00000; объем 25168
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:10:00.000 | | Новая свеча 20.12.2012 10:05:00: 150740,00000;150770,00000;150620,00000;150740,00000; объем 11846
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:15:00.000 | | Новая свеча 20.12.2012 10:10:00: 150750,00000;150940,00000;150710,00000;150920,00000; объем 8850
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:20:00.000 | | Новая свеча 20.12.2012 10:15:00: 150920,00000;151080,00000;150860,00000;150940,00000; объем 8711
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:25:00.000 | | Новая свеча 20.12.2012 10:20:00: 150940,00000;151050,00000;150920,00000;150990,00000; объем 4658
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:30:00.000 | | Новая свеча 20.12.2012 10:25:00: 150980,00000;151070,00000;150870,00000;150870,00000; объем 3961
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:35:00.000 | | Новая свеча 20.12.2012 10:30:00: 150880,00000;151000,00000;150830,00000;150930,00000; объем 4490
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:40:00.000 | | Новая свеча 20.12.2012 10:35:00: 150930,00000;150980,00000;150750,00000;150820,00000; объем 7417
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:45:01.000 | | Новая свеча 20.12.2012 10:40:00: 150800,00000;150880,00000;150780,00000;150860,00000; объем 2320
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:50:01.000 | | Новая свеча 20.12.2012 10:45:00: 150860,00000;150940,00000;150800,00000;150920,00000; объем 3868
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:55:00.000 | | Новая свеча 20.12.2012 10:50:00: 150920,00000;150960,00000;150850,00000;150900,00000; объем 2458
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:55:00.000 | | Регистрация новой заявки на Sell с ценой 150900,00000 и объемом 1.
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:55:14.000 | | Новая позиция: test account-SPFB.RTS@RTS=-1.
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:55:14.000 | | Заявка 63381939 больше не активна.
SS_SPFB.RTS@RTS_test account | 20.12.2012 05:55:14.000 | | Новая Sell сделка 1 по цене 150900,00000 на 1 заявки 63381939.
SS_SPFB.RTS@RTS_test account | 20.12.2012 06:00:00.000 | | Новая свеча 20.12.2012 10:55:00: 150880,00000;150950,00000;150840,00000;150910,00000; объем 3226
SS_SPFB.RTS@RTS_test account | 20.12.2012 06:05:00.000 | | Новая свеча 20.12.2012 11:00:00: 150910,00000;150950,00000;150820,00000;150930,00000; объем 4422
код подправленной SampleHistoryTesting.
namespace SampleHistoryTesting
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using MessageBox = System.Windows.MessageBox;
using Ecng.Common;
using Ecng.Xaml;
using Ecng.Collections;
using StockSharp.Algo.Candles;
using StockSharp.Algo.Reporting;
using StockSharp.Algo.Storages;
using StockSharp.Algo.Strategies;
using StockSharp.Algo.Testing;
using StockSharp.Algo.Indicators.Trend;
using StockSharp.Logging;
using StockSharp.BusinessEntities;
using StockSharp.Xaml;
using ChartArea = StockSharp.Xaml.ChartArea;
using System.Linq;
public partial class MainWindow
{
private Strategy _strategy;
private ICollection<EquityData> _curveItems;
private EmulationTrader _trader;
private readonly LogManager _logManager = new LogManager();
private readonly MonitorWindow _monitor = new MonitorWindow();
private DateTime _startEmulationTime;
public MainWindow()
{
InitializeComponent();
_logManager.Listeners.Add(new GuiLogListener(_monitor));
_logManager.Listeners.Add(new FileLogListener("log.txt"));
_monitor.Show();
}
private void FindPathClick(object sender, RoutedEventArgs e)
{
var dlg = new FolderBrowserDialog();
if (!HistoryPath.Text.IsEmpty())
dlg.SelectedPath = HistoryPath.Text;
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
HistoryPath.Text = dlg.SelectedPath;
}
}
private void StartBtnClick(object sender, RoutedEventArgs e)
{
// если процесс был запущен, то его останавливаем
if (_trader != null && _trader.State != EmulationStates.Stopped)
{
StartBtn.IsEnabled = false;
_strategy.Stop();
_trader.Stop();
_logManager.Sources.Clear();
return;
}
InitChart();
// создаем тестовый инструмент, на котором будет производится тестирование
var security = new Security
{
//Id = "RIU9@RTS", // по идентификатору инструмента будет искаться папка с историческими маркет данными
//Code = "RIU9",
//Name = "RTS-9.09",
//MinStepSize = 5,
//MinStepPrice = 2,
//Exchange = Exchange.Rts,
Id = "SPFB.RTS@RTS",
Code = "RTS",
Class = "SPFB",
MinStepSize = 5m,
Decimals = 0,
Exchange = Exchange.Rts
};
// тестовый портфель
var portfolio = new Portfolio { Name = "test account", BeginValue = 1000000m };
// хранилище, через которое будет производиться доступ к тиковой и котировочной базе
var storageRegistry = new StorageRegistry();
// изменяем путь, используемый по умолчанию
((LocalMarketDataDrive)storageRegistry.DefaultDrive).Path = @"C:\History";
var timeFrame = TimeSpan.FromMinutes(5);
// в реальности период может быть другим, и это зависит от объема данных,
// хранящихся по пути HistoryPath,
var startTime = new DateTime(2012, 12, 20);
var stopTime = new DateTime(2012, 12, 31);
_trader = new EmulationTrader(
new[] { security },
new[] { portfolio })
{
MarketTimeChangedInterval = timeFrame,
StorageRegistry = storageRegistry,
// необходимо включать только если есть история стаканов и нужно получить более точное тестирование
UseMarketDepth = false,
};
// история по стакана отсутствует, но стаканы необходимы для стратегии,
// то их можно сгенерировать на основании цен последних сделок
//_trader.RegisterMarketDepth(new TrendMarketDepthGenerator(security)
//{
// // стакан для инструмента в истории обновляется раз в секунду
// Interval = TimeSpan.FromSeconds(1),
//});
// соединяемся с трейдером и запускаем экспорт,
// чтобы инициализировать переданными инструментами и портфелями необходимые свойства EmulationTrader
_trader.NewMyTrades += Draw;
_trader.Connect();
_trader.StartExport();
var candleManager = new CandleManager(_trader);
var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);
candleManager.Processing += Draw;
candleManager.Start(series);
// создаем торговую стратегию, скользящие средние на 80 5-минуток и 10 5-минуток
_strategy = new SmaStrategy(series, new SimpleMovingAverage { Length = 10 }, new SimpleMovingAverage { Length = 5 })
{
Volume = 1,
Portfolio = portfolio,
Security = security,
Trader = _trader
};
// копируем параметры на визуальную панель
ParametersPanel.Parameters.Clear();
ParametersPanel.Parameters.AddRange(_strategy.StatisticManager.Parameters);
if (_curveItems == null)
_curveItems = Curve.CreateCurve(_strategy.Name, Colors.DarkGreen);
else
_curveItems.Clear();
_strategy.PnLChanged += () =>
{
var data = new EquityData
{
Time = _strategy.GetMarketTime(),
Value = _strategy.PnL,
};
this.GuiAsync(() => _curveItems.Add(data));
};
_logManager.Sources.Add(_strategy);
// задаем шаг ProgressBar
var progressStep = ((stopTime - startTime).Ticks / 100).To<TimeSpan>();
var nextTime = startTime + progressStep;
TestingProcess.Maximum = 100;
TestingProcess.Value = 0;
// и подписываемся на событие изменения времени, чтобы обновить ProgressBar
_trader.MarketTimeChanged += diff =>
{
if (_trader.CurrentTime >= nextTime || _trader.CurrentTime >= stopTime)
{
nextTime += progressStep;
this.GuiAsync(() => TestingProcess.Value++);
}
};
_trader.StateChanged += (oldState, newState) =>
{
if (_trader.State == EmulationStates.Stopped)
{
this.GuiAsync(() =>
{
StartBtn.IsEnabled = true;
if (_trader.IsFinished)
{
TestingProcess.Value = TestingProcess.Maximum;
MessageBox.Show(this, "Закончено за " + (DateTime.Now - _startEmulationTime));
}
else
MessageBox.Show(this, "Отменено");
});
}
else if (_trader.State == EmulationStates.Started)
{
// запускаем стратегию когда эмулятор запустился
_strategy.Start();
}
};
Report.IsEnabled = true;
_startEmulationTime = DateTime.Now;
// запускаем эмуляцию, задавая период тестирования (startTime, stopTime).
_trader.Start(startTime, stopTime);
}
private void ReportClick(object sender, RoutedEventArgs e)
{
// сгерерировать отчет по прошедшему тестированию
// Внимание! сделок и заявок может быть большое количество,
// поэтому Excel отчет может тормозить
new ExcelStrategyReport(_strategy, "sma.xls").Generate();
// открыть отчет
Process.Start("sma.xls");
}
/// <summary>
/// Окно для отображения графика со свечками
/// </summary>
private ChartWindow _chartWindow;
/*----------Элементы для графика------------*/
private ChartCandleElement _candlesElem;
private ChartTradeElement _tradeElement;
private ChartArea _area1;
/*------------------------------------------*/
/// <summary>
/// Инициализируем чарт
/// </summary>
private void InitChart()
{
_chartWindow = new ChartWindow();
_chartWindow.MakeHideable();
/* ----- Добавляем все нужные участки для нашего графика*/
_area1 = new ChartArea();
_chartWindow.Chart.Areas.Add(_area1);
_candlesElem = new ChartCandleElement();
_area1.Elements.Add(_candlesElem);
_tradeElement = new ChartTradeElement();
_area1.Elements.Add(_tradeElement);
_chartWindow.Show();
}
private void Draw(CandleSeries series, Candle candle)
{
if (candle.State == CandleStates.Finished)
{
this.GuiAsync(() => _chartWindow.Chart.ProcessValues(candle.OpenTime, new Dictionary<IChartElement, object>
{
{_candlesElem, candle},
}));
}
}
private void Draw(IEnumerable<MyTrade> trade)
{
this.GuiAsync(
() => _chartWindow.Chart.ProcessValues(trade.Last().Trade.Time, new Dictionary<IChartElement, object>
{
{_tradeElement,trade.Last()},
}));
}
}
}