StopLoss и тестирование на истории
Добрый день!
Суть проблемы, начиная с версии StockSharp 4.1.3 (далее SS) не работает StopLoss,причем только с EmulationTrader. Более корректно - при включенном IsTrailing = true, StopLoss ведет себя как будто IsTrailing отключен. Конечно это суждение основанное только на результатах теста, что реально происходит мне неизвестно.
- Для приготовления теста взят "SampleHistoryTesting" "SS 4.1.4" из него удален класс SmaStrategy и вставлен простой класс для тестирования StopLoss приведенный ниже.
- Тестирование проводилось на всех SS начиная с версии "SS 4.1.2" и заканчивая "SS 4.1.4 bild 19213"
- Тестирование проводилось на одних и тех же данных "SBER@EQBR" 02.05.12 по 10.08.12. Тиковые сделки получены через программу "Hydra (SS 4.1.3)", а так же "RIU9@RTS"
- Тестирование проводилось с разными значениями ProtectiveLevel начиная с минимального =Security.MinStepSize.
- Для исключения влияния характера исходных данных на полученный результат менялась дата начала теста. Картина в целом оставалась такой же, менялось только количество сделок StopLoss стратегии совершенных в начале тестирования.
Результаты тестирования
- В версии "SS 4.1.2" получен адекватный результат, ниже приведен фрагмент лога и картинка работы стратегии
- Начиная с версии "SS 4.1.3" результаты были повторяющимися но не соответствующими ожиданиям в приведенном ниже логе и на картинке видно как StopLoss срабатывает один раз а затем после следующей сделки находясь в активном режиме не реагирует на изменение цены даже при ProtectiveLevel=Security.MinStepSize.
С уважением GII
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 ();
}
}
}
