StopLoss и тестирование на истории
Добрый день!
Суть проблемы, начиная с версии StockSharp 4.1.3 (далее SS) не работает StopLoss,причем только с EmulationTrader. Более корректно - при включенном IsTrailing = true, StopLoss ведет себя как будто IsTrailing отключен. Конечно это суждение основанное только на результатах теста, что реально происходит мне неизвестно.
1. Для приготовления теста взят "SampleHistoryTesting" "SS 4.1.4" из него удален класс SmaStrategy и вставлен простой класс для тестирования StopLoss приведенный ниже.
2. Тестирование проводилось на всех SS начиная с версии "SS 4.1.2" и заканчивая "SS 4.1.4 bild 19213"
3. Тестирование проводилось на одних и тех же данных "SBER@EQBR" 02.05.12 по 10.08.12. Тиковые сделки получены через программу "Hydra (SS 4.1.3)", а так же "RIU9@RTS"
4. Тестирование проводилось с разными значениями ProtectiveLevel начиная с минимального =Security.MinStepSize.
5. Для исключения влияния характера исходных данных на полученный результат менялась дата начала теста. Картина в целом оставалась такой же, менялось только количество сделок StopLoss стратегии совершенных в начале тестирования.
Результаты тестирования
1. В версии "SS 4.1.2" получен адекватный результат, ниже приведен фрагмент лога и картинка работы стратегии
2. Начиная с версии "SS 4.1.3" результаты были повторяющимися но не соответствующими ожиданиям в приведенном ниже логе и на картинке видно как StopLoss срабатывает один раз а затем после следующей сделки находясь в активном режиме не реагирует на изменение цены даже при ProtectiveLevel=Security.MinStepSize.
С уважением GII
Code
using System;
using System.Collections.Generic;
using System.Linq;
using StockSharp.Algo.Candles;
using StockSharp.Algo.Logging;
using StockSharp.Algo;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
namespace SampleHistoryTesting
{
class MyStopLossStrategy : Strategy
{
private readonly CandleSeries _series;
private readonly TimeSpan _timeFrame;
private Exchange _excheng;
private Random _random;
private Order _order=new Order();
private static readonly object Locker = new object ();
public MyStopLossStrategy( CandleSeries series, TimeSpan timeFrame )
{
_series = series;
_timeFrame = timeFrame;
}
protected override void OnStarted()
{
_excheng = Security.Exchange;
_series
.WhenCandlesFinished ()
.Do ( ProcessCandle ).Apply ( this );
// Инициализируем генератор случ величин
_random = new Random ( 1 );
base.OnStarted ();
}
private void ProcessCandle( Candle candle )
{
/* Три условия вхождения в сделку
* 1. пришла последняя свечка
* 2. Protective стратегия больше не активна
*/
var lastTime = _timeFrame.GetCandleBounds ( Trader.GetMarketTime (_excheng) ).Min - _timeFrame;
#region InfoLog
this.AddInfoLog(string.Format("LastTime / candle.OpenTime // {0} / {1} //", lastTime, candle.OpenTime));
this.AddInfoLog(string.Format("StopLoss (активна -true) = {0}", IsActiveChildStrat()));
#endregion
lock (Locker)
{
//var lastTime = Trader.GetMarketTime ( _excheng );
//var endInterval = candle.CloseTime + TimeSpan.FromSeconds ( 5 );
if (lastTime <= candle.OpenTime)
{
if (_order.State == OrderStates.Active) CancelActiveOrders ();
if (!IsActiveChildStrat ())
{
_order = null;
// Определяем направление сделки
var rd = 1 - 2 * _random.NextDouble (); // -1 < rd < 1
var direction = OrderDirections.Sell;
if (rd >= 0) direction = OrderDirections.Buy;
_order = this.CreateOrder ( direction, (decimal)Security.GetCurrentPrice ( direction ), Volume );
//Обрабатываем новые сделки только от _order.
_order.WhenNewTrades ().Do ( NewMyTrade ).Apply ( this );
RegisterOrder ( _order );
this.AddOrderInfoLog ( _order, "" );
}
}
}
}
private void NewMyTrade( IEnumerable<MyTrade> trades )
{
try
{
lock (Locker)
{
var trade = trades.Last ();
var sl = new StopLossStrategy ( trade, (int)UnitTypes.Absolute )
{
IsTrailing = true,
ProtectiveLevel =Security.MinStepSize,
Security = Security,
};
// Удоляем следы работы дочерней стратегии
sl.WhenStopped ().Do ( strategy =>
{
ChildStrategies.Remove ( strategy );
this.AddInfoLog ( string.Format ( "Кол. StopLoss активных стратегий = {0}",ChildStrategies.Count));
} ).Once ().Apply ( this );
ChildStrategies.Add ( sl );
this.AddInfoLog ( string.Format ( "ProtectivePrice / ProtectiveDirection= //{0} / {1} ", sl.ActivationPrice.ToString("F2"), sl.ProtectiveDirection.ToString() ) );
this.AddInfoLog ( string.Format ( "StopLoss = {0}", sl.IsActivated.ToString() ) );
}
}
catch (Exception e)
{
this.AddErrorLog ( string.Format ( "<NewMyTrade> Err {0}", e ) );
}
}
/* Метод проверяет активность одной из нескольких стратегий,
* если хотя бы одна активна возвращает true
*/
public bool IsActiveChildStrat()
{
try
{
if (ChildStrategies.Count == 0) return false;
if (ChildStrategies.Count > 0) return true;
/*
if (ChildStrategies.Any ( childStrategy => childStrategy.ProcessState == ProcessStates.Started || childStrategy.ProcessState == ProcessStates.Stopping ))
{
return true;
}
*/
}
catch (Exception e)
{
this.AddErrorLog ( string.Format ( "<IsActiveChildStrat> Err {0}", e ) );
}
return false;
}
protected override void OnStopping()
{
//останавливаем все доч. стратегии
foreach (var str in ChildStrategies) { str.Stop (); }
ChildStrategies.Clear ();
CancelActiveOrders ();
base.OnStopping ();
}
}
}