Стратегия BHS System
Обзор
BHS System — это порт оригинального советника MetaTrader 5 на платформу StockSharp, работающий по логике пробоя. Стратегия отслеживает положение цены относительно адаптивной скользящей средней Кауфмана (Kaufman Adaptive Moving Average, AMA). Если свеча закрывается выше AMA, готовится покупка через отложенный buy stop; если закрытие ниже AMA — готовится sell stop. Заявки выставляются только на «круглых» ценовых уровнях, определяемых пользователем, что полностью повторяет механику исходного MQL-кода.
Логика торговли
- После завершения каждой свечи вычисляются ближайшие сверху и снизу округлённые уровни. Для расчёта используется шаг в пунктах, заданный пользователем, и минимальный шаг цены инструмента.
- Текущее закрытие сравнивается с предыдущим значением AMA (значение индикатора со смещением на одну свечу, как и в функции
iAMAGet(1)исходного робота). - При отсутствии позиции и активных заявок:
- если закрытие выше AMA, выставляется buy stop на ближайшем округлённом уровне выше цены;
- если закрытие ниже AMA, выставляется sell stop на ближайшем округлённом уровне ниже цены.
- Каждая заявка имеет ограниченный срок жизни в часах. По его истечении невыполненные заявки снимаются, что соответствует параметру Expiration в MT5.
- После исполнения отложенного ордера противоположная заявка отменяется, создаётся защитный стоп по заданной дистанции и запускается механизм трейлинга.
- Трейлинг переносит стоп только тогда, когда цена продвинулась на величину «дистанция + шаг трейлинга», что исключает постоянные модификации и повторяет дискретную схему MQL-версии.
Управление рисками
- Первичный стоп-лосс: для длинных и коротких позиций задаются отдельные расстояния в пунктах. После сделки они переводятся в абсолютные цены и используются для размещения защитного стоп-ордера.
- Трейлинг-стоп: расстояния для лонга и шорта задаются отдельно. Перенос стопа выполняется только при улучшении не менее чем на один шаг трейлинга, что предотвращает излишние корректировки во флэте.
- Истечение заявок: каждая заявка хранит время создания. Если она активна дольше разрешённого срока, стратегия её отменяет, не позволяя заявкам «зависать» в рынке.
Параметры
OrderVolume— объём заявок (в лотах) для входа и защитных ордеров.StopLossBuyPoints/StopLossSellPoints— расстояние до первоначального стоп-лосса в пунктах для длинных и коротких сделок.TrailingStopBuyPoints/TrailingStopSellPoints— дистанция трейлинг-стопа в пунктах для лонга и шорта.TrailingStepPoints— минимальное дополнительное смещение (в пунктах) перед очередным переносом стопа.RoundStepPoints— число пунктов, определяющее сетку округлённых цен.ExpirationHours— срок жизни отложенных ордеров в часах (0 — бессрочно).AmaLength,AmaFastPeriod,AmaSlowPeriod— параметры адаптивной скользящей средней Кауфмана.CandleType— тип и таймфрейм свечей, используемых в расчётах.
Особенности реализации
- Используется индикатор
KaufmanAdaptiveMovingAverageиз библиотеки StockSharp, код оформлен с файловой областью имён согласно стандартам репозитория. - Для торговли применяются высокоуровневые методы (
BuyStop,SellStop,CancelOrder), индикаторные значения не извлекаются черезGetValue. - При наличии графического окружения выводятся свечи, линия AMA и собственные сделки стратегии для наглядного контроля.
- Один и тот же ордер используется как для начального стопа, так и для последующих трейлинговых переносов, что избегает избыточных заявок.
- В коде сохранены комментарии на английском языке и полностью воспроизведены условия срабатывания трейлинга из MQL-версии, обеспечивая идентичность поведения.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Breakout strategy that places stop orders on rounded price levels guided by a Kaufman adaptive moving average.
/// </summary>
public class BhsSystemStrategy : Strategy
{
private readonly StrategyParam<decimal> _orderVolume;
private readonly StrategyParam<int> _stopLossBuyPoints;
private readonly StrategyParam<int> _stopLossSellPoints;
private readonly StrategyParam<int> _trailingStopBuyPoints;
private readonly StrategyParam<int> _trailingStopSellPoints;
private readonly StrategyParam<int> _trailingStepPoints;
private readonly StrategyParam<int> _roundStepPoints;
private readonly StrategyParam<decimal> _expirationHours;
private readonly StrategyParam<int> _amaLength;
private readonly StrategyParam<int> _amaFastPeriod;
private readonly StrategyParam<int> _amaSlowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _previousAma;
private bool _hasPreviousAma;
private decimal? _buyStopLevel;
private decimal? _sellStopLevel;
private DateTimeOffset? _buyOrderTime;
private DateTimeOffset? _sellOrderTime;
private decimal _entryPrice;
private decimal _highestSinceEntry;
private decimal _lowestSinceEntry;
/// <summary>
/// Trade volume used for both entry and protective orders.
/// </summary>
public decimal OrderVolume
{
get => _orderVolume.Value;
set => _orderVolume.Value = value;
}
/// <summary>
/// Stop-loss distance for long trades expressed in points.
/// </summary>
public int StopLossBuyPoints
{
get => _stopLossBuyPoints.Value;
set => _stopLossBuyPoints.Value = value;
}
/// <summary>
/// Stop-loss distance for short trades expressed in points.
/// </summary>
public int StopLossSellPoints
{
get => _stopLossSellPoints.Value;
set => _stopLossSellPoints.Value = value;
}
/// <summary>
/// Trailing stop distance in points for long positions.
/// </summary>
public int TrailingStopBuyPoints
{
get => _trailingStopBuyPoints.Value;
set => _trailingStopBuyPoints.Value = value;
}
/// <summary>
/// Trailing stop distance in points for short positions.
/// </summary>
public int TrailingStopSellPoints
{
get => _trailingStopSellPoints.Value;
set => _trailingStopSellPoints.Value = value;
}
/// <summary>
/// Minimum step in points between trailing stop updates.
/// </summary>
public int TrailingStepPoints
{
get => _trailingStepPoints.Value;
set => _trailingStepPoints.Value = value;
}
/// <summary>
/// Step used to build rounded trigger prices in points.
/// </summary>
public int RoundStepPoints
{
get => _roundStepPoints.Value;
set => _roundStepPoints.Value = value;
}
/// <summary>
/// Lifetime of pending entry orders in hours.
/// </summary>
public decimal ExpirationHours
{
get => _expirationHours.Value;
set => _expirationHours.Value = value;
}
/// <summary>
/// Main period of the adaptive moving average.
/// </summary>
public int AmaLength
{
get => _amaLength.Value;
set => _amaLength.Value = value;
}
/// <summary>
/// Fast smoothing constant of the adaptive moving average.
/// </summary>
public int AmaFastPeriod
{
get => _amaFastPeriod.Value;
set => _amaFastPeriod.Value = value;
}
/// <summary>
/// Slow smoothing constant of the adaptive moving average.
/// </summary>
public int AmaSlowPeriod
{
get => _amaSlowPeriod.Value;
set => _amaSlowPeriod.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="BhsSystemStrategy"/> class.
/// </summary>
public BhsSystemStrategy()
{
_orderVolume = Param(nameof(OrderVolume), 0.1m)
.SetGreaterThanZero()
.SetDisplay("Order Volume", "Lot size used for entry orders", "Trading");
_stopLossBuyPoints = Param(nameof(StopLossBuyPoints), 300)
.SetNotNegative()
.SetDisplay("Stop Loss Buy (points)", "Distance in points for long stop loss", "Risk");
_stopLossSellPoints = Param(nameof(StopLossSellPoints), 300)
.SetNotNegative()
.SetDisplay("Stop Loss Sell (points)", "Distance in points for short stop loss", "Risk");
_trailingStopBuyPoints = Param(nameof(TrailingStopBuyPoints), 100)
.SetNotNegative()
.SetDisplay("Trailing Stop Buy (points)", "Trailing distance in points for long positions", "Risk");
_trailingStopSellPoints = Param(nameof(TrailingStopSellPoints), 100)
.SetNotNegative()
.SetDisplay("Trailing Stop Sell (points)", "Trailing distance in points for short positions", "Risk");
_trailingStepPoints = Param(nameof(TrailingStepPoints), 10)
.SetNotNegative()
.SetDisplay("Trailing Step (points)", "Minimum step in points between trailing updates", "Risk");
_roundStepPoints = Param(nameof(RoundStepPoints), 2000)
.SetGreaterThanZero()
.SetDisplay("Round Step (points)", "Number of points used to build round price levels", "Execution");
_expirationHours = Param(nameof(ExpirationHours), 1m)
.SetNotNegative()
.SetDisplay("Order Expiration (hours)", "Lifetime of pending entry orders in hours", "Execution");
_amaLength = Param(nameof(AmaLength), 15)
.SetGreaterThanZero()
.SetDisplay("AMA Length", "Adaptive moving average period", "Indicators");
_amaFastPeriod = Param(nameof(AmaFastPeriod), 2)
.SetGreaterThanZero()
.SetDisplay("AMA Fast Period", "Fast smoothing constant for AMA", "Indicators");
_amaSlowPeriod = Param(nameof(AmaSlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("AMA Slow Period", "Slow smoothing constant for AMA", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Time frame used for analysis", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousAma = 0m;
_hasPreviousAma = false;
_buyStopLevel = null;
_sellStopLevel = null;
_buyOrderTime = null;
_sellOrderTime = null;
_entryPrice = 0m;
_highestSinceEntry = 0m;
_lowestSinceEntry = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Configure the adaptive moving average with user parameters.
var ama = new KaufmanAdaptiveMovingAverage
{
Length = AmaLength,
FastSCPeriod = AmaFastPeriod,
SlowSCPeriod = AmaSlowPeriod
};
// Subscribe to candle data and bind indicator updates.
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ama, ProcessCandle)
.Start();
// Draw price, indicator and trades if a chart is available.
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ama);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal amaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPreviousAma)
{
_previousAma = amaValue;
_hasPreviousAma = true;
return;
}
// Check protective stops
CheckStopLoss(candle);
CheckTrailingStop(candle);
// Expire old pending levels
CancelExpiredLevels();
// Check if pending levels are triggered
CheckPendingTriggers(candle);
var price = candle.ClosePrice;
var (_, priceCeil, priceFloor) = CalculateRoundLevels(price);
// Track extremes for trailing
if (Position > 0 && price > _highestSinceEntry)
_highestSinceEntry = price;
if (Position < 0 && (_lowestSinceEntry == 0 || price < _lowestSinceEntry))
_lowestSinceEntry = price;
var hasPendingLevels = _buyStopLevel.HasValue || _sellStopLevel.HasValue;
if (Position == 0 && !hasPendingLevels)
{
if (price > _previousAma)
{
_buyStopLevel = priceCeil;
_buyOrderTime = candle.OpenTime;
}
else if (price < _previousAma)
{
_sellStopLevel = priceFloor;
_sellOrderTime = candle.OpenTime;
}
}
_previousAma = amaValue;
}
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
if (trade?.Trade == null) return;
if (Position != 0m && _entryPrice == 0m)
{
_entryPrice = trade.Trade.Price;
_highestSinceEntry = trade.Trade.Price;
_lowestSinceEntry = trade.Trade.Price;
}
if (Position == 0m)
{
_entryPrice = 0m;
_highestSinceEntry = 0m;
_lowestSinceEntry = 0m;
}
}
private void CheckStopLoss(ICandleMessage candle)
{
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && StopLossBuyPoints > 0)
{
var stopPrice = _entryPrice - StopLossBuyPoints * step;
if (candle.LowPrice <= stopPrice)
{
SellMarket(Math.Abs(Position));
return;
}
}
if (Position < 0 && StopLossSellPoints > 0)
{
var stopPrice = _entryPrice + StopLossSellPoints * step;
if (candle.HighPrice >= stopPrice)
{
BuyMarket(Math.Abs(Position));
}
}
}
private void CheckTrailingStop(ICandleMessage candle)
{
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && TrailingStopBuyPoints > 0)
{
var trailingDist = TrailingStopBuyPoints * step;
var trailingStep = TrailingStepPoints * step;
var profit = _highestSinceEntry - _entryPrice;
if (profit > trailingDist + trailingStep)
{
var trailStop = _highestSinceEntry - trailingDist;
if (candle.LowPrice <= trailStop)
{
SellMarket(Math.Abs(Position));
return;
}
}
}
if (Position < 0 && TrailingStopSellPoints > 0 && _lowestSinceEntry > 0)
{
var trailingDist = TrailingStopSellPoints * step;
var trailingStep = TrailingStepPoints * step;
var profit = _entryPrice - _lowestSinceEntry;
if (profit > trailingDist + trailingStep)
{
var trailStop = _lowestSinceEntry + trailingDist;
if (candle.HighPrice >= trailStop)
{
BuyMarket(Math.Abs(Position));
}
}
}
}
private void CheckPendingTriggers(ICandleMessage candle)
{
if (_buyStopLevel.HasValue && Position <= 0 && candle.HighPrice >= _buyStopLevel.Value)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(OrderVolume);
_buyStopLevel = null;
_buyOrderTime = null;
_sellStopLevel = null;
_sellOrderTime = null;
}
if (_sellStopLevel.HasValue && Position >= 0 && candle.LowPrice <= _sellStopLevel.Value)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(OrderVolume);
_sellStopLevel = null;
_sellOrderTime = null;
_buyStopLevel = null;
_buyOrderTime = null;
}
}
private void CancelExpiredLevels()
{
if (ExpirationHours <= 0m)
return;
var expiration = TimeSpan.FromHours((double)ExpirationHours);
var now = CurrentTime;
if (_buyOrderTime.HasValue && now - _buyOrderTime.Value >= expiration)
{
_buyStopLevel = null;
_buyOrderTime = null;
}
if (_sellOrderTime.HasValue && now - _sellOrderTime.Value >= expiration)
{
_sellStopLevel = null;
_sellOrderTime = null;
}
}
private (decimal rounded, decimal ceil, decimal floor) CalculateRoundLevels(decimal price)
{
var point = Security?.PriceStep ?? 1m;
var stepPoints = RoundStepPoints;
if (point <= 0m || stepPoints <= 0)
return (price, price, price);
var step = stepPoints * point;
if (step <= 0m)
return (price, price, price);
var ratio = price / step;
var roundedIndex = decimal.Round(ratio, 0, MidpointRounding.AwayFromZero);
var priceRound = roundedIndex * step;
var ceilIndex = decimal.Ceiling((priceRound + step / 2m) / step);
var floorIndex = decimal.Floor((priceRound - step / 2m) / step);
var priceCeil = ceilIndex * step;
var priceFloor = floorIndex * step;
return (priceRound, priceCeil, priceFloor);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import KaufmanAdaptiveMovingAverage
from StockSharp.Algo.Strategies import Strategy
class bhs_system_strategy(Strategy):
def __init__(self):
super(bhs_system_strategy, self).__init__()
self._order_volume = self.Param("OrderVolume", 0.1)
self._stop_loss_buy_points = self.Param("StopLossBuyPoints", 300)
self._stop_loss_sell_points = self.Param("StopLossSellPoints", 300)
self._trailing_stop_buy_points = self.Param("TrailingStopBuyPoints", 100)
self._trailing_stop_sell_points = self.Param("TrailingStopSellPoints", 100)
self._trailing_step_points = self.Param("TrailingStepPoints", 10)
self._round_step_points = self.Param("RoundStepPoints", 2000)
self._expiration_hours = self.Param("ExpirationHours", 1.0)
self._ama_length = self.Param("AmaLength", 15)
self._ama_fast_period = self.Param("AmaFastPeriod", 2)
self._ama_slow_period = self.Param("AmaSlowPeriod", 30)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._previous_ama = 0.0
self._has_previous_ama = False
self._buy_stop_level = None
self._sell_stop_level = None
self._buy_order_time = None
self._sell_order_time = None
self._entry_price = 0.0
self._highest_since_entry = 0.0
self._lowest_since_entry = 0.0
@property
def OrderVolume(self):
return self._order_volume.Value
@property
def StopLossBuyPoints(self):
return self._stop_loss_buy_points.Value
@property
def StopLossSellPoints(self):
return self._stop_loss_sell_points.Value
@property
def TrailingStopBuyPoints(self):
return self._trailing_stop_buy_points.Value
@property
def TrailingStopSellPoints(self):
return self._trailing_stop_sell_points.Value
@property
def TrailingStepPoints(self):
return self._trailing_step_points.Value
@property
def RoundStepPoints(self):
return self._round_step_points.Value
@property
def ExpirationHours(self):
return self._expiration_hours.Value
@property
def AmaLength(self):
return self._ama_length.Value
@property
def AmaFastPeriod(self):
return self._ama_fast_period.Value
@property
def AmaSlowPeriod(self):
return self._ama_slow_period.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(bhs_system_strategy, self).OnStarted2(time)
ama = KaufmanAdaptiveMovingAverage()
ama.Length = self.AmaLength
ama.FastSCPeriod = self.AmaFastPeriod
ama.SlowSCPeriod = self.AmaSlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ama, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ama)
self.DrawOwnTrades(area)
def OnOwnTradeReceived(self, trade):
super(bhs_system_strategy, self).OnOwnTradeReceived(trade)
if trade is None or trade.Trade is None:
return
pos = float(self.Position)
if pos != 0 and self._entry_price == 0.0:
self._entry_price = float(trade.Trade.Price)
self._highest_since_entry = float(trade.Trade.Price)
self._lowest_since_entry = float(trade.Trade.Price)
if pos == 0:
self._entry_price = 0.0
self._highest_since_entry = 0.0
self._lowest_since_entry = 0.0
def _process_candle(self, candle, ama_value):
if candle.State != CandleStates.Finished:
return
ama_val = float(ama_value)
if not self._has_previous_ama:
self._previous_ama = ama_val
self._has_previous_ama = True
return
self._check_stop_loss(candle)
self._check_trailing_stop(candle)
self._cancel_expired_levels()
self._check_pending_triggers(candle)
price = float(candle.ClosePrice)
price_ceil, price_floor = self._calculate_round_levels(price)
pos = float(self.Position)
if pos > 0 and price > self._highest_since_entry:
self._highest_since_entry = price
if pos < 0 and (self._lowest_since_entry == 0 or price < self._lowest_since_entry):
self._lowest_since_entry = price
has_pending = self._buy_stop_level is not None or self._sell_stop_level is not None
if float(self.Position) == 0 and not has_pending:
if price > self._previous_ama:
self._buy_stop_level = price_ceil
self._buy_order_time = candle.OpenTime
elif price < self._previous_ama:
self._sell_stop_level = price_floor
self._sell_order_time = candle.OpenTime
self._previous_ama = ama_val
def _check_stop_loss(self, candle):
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None else 1.0
pos = float(self.Position)
if pos > 0 and self.StopLossBuyPoints > 0:
stop_price = self._entry_price - self.StopLossBuyPoints * step
if float(candle.LowPrice) <= stop_price:
self.SellMarket(abs(pos))
return
if pos < 0 and self.StopLossSellPoints > 0:
stop_price = self._entry_price + self.StopLossSellPoints * step
if float(candle.HighPrice) >= stop_price:
self.BuyMarket(abs(pos))
def _check_trailing_stop(self, candle):
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None else 1.0
pos = float(self.Position)
if pos > 0 and self.TrailingStopBuyPoints > 0:
trailing_dist = self.TrailingStopBuyPoints * step
trailing_step = self.TrailingStepPoints * step
profit = self._highest_since_entry - self._entry_price
if profit > trailing_dist + trailing_step:
trail_stop = self._highest_since_entry - trailing_dist
if float(candle.LowPrice) <= trail_stop:
self.SellMarket(abs(pos))
return
if pos < 0 and self.TrailingStopSellPoints > 0 and self._lowest_since_entry > 0:
trailing_dist = self.TrailingStopSellPoints * step
trailing_step = self.TrailingStepPoints * step
profit = self._entry_price - self._lowest_since_entry
if profit > trailing_dist + trailing_step:
trail_stop = self._lowest_since_entry + trailing_dist
if float(candle.HighPrice) >= trail_stop:
self.BuyMarket(abs(pos))
def _check_pending_triggers(self, candle):
pos = float(self.Position)
if self._buy_stop_level is not None and pos <= 0 and float(candle.HighPrice) >= self._buy_stop_level:
if pos < 0:
self.BuyMarket(abs(pos))
self.BuyMarket(float(self.OrderVolume))
self._buy_stop_level = None
self._buy_order_time = None
self._sell_stop_level = None
self._sell_order_time = None
pos = float(self.Position)
if self._sell_stop_level is not None and pos >= 0 and float(candle.LowPrice) <= self._sell_stop_level:
if pos > 0:
self.SellMarket(abs(pos))
self.SellMarket(float(self.OrderVolume))
self._sell_stop_level = None
self._sell_order_time = None
self._buy_stop_level = None
self._buy_order_time = None
def _cancel_expired_levels(self):
if float(self.ExpirationHours) <= 0:
return
expiration = TimeSpan.FromHours(float(self.ExpirationHours))
now = self.CurrentTime
if self._buy_order_time is not None and now - self._buy_order_time >= expiration:
self._buy_stop_level = None
self._buy_order_time = None
if self._sell_order_time is not None and now - self._sell_order_time >= expiration:
self._sell_stop_level = None
self._sell_order_time = None
def _calculate_round_levels(self, price):
sec = self.Security
point = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None else 1.0
step_points = self.RoundStepPoints
if point <= 0 or step_points <= 0:
return (price, price)
step = step_points * point
if step <= 0:
return (price, price)
ratio = price / step
rounded_index = round(ratio)
price_round = rounded_index * step
import math
ceil_index = math.ceil((price_round + step / 2.0) / step)
floor_index = math.floor((price_round - step / 2.0) / step)
price_ceil = ceil_index * step
price_floor = floor_index * step
return (price_ceil, price_floor)
def OnReseted(self):
super(bhs_system_strategy, self).OnReseted()
self._previous_ama = 0.0
self._has_previous_ama = False
self._buy_stop_level = None
self._sell_stop_level = None
self._buy_order_time = None
self._sell_order_time = None
self._entry_price = 0.0
self._highest_since_entry = 0.0
self._lowest_since_entry = 0.0
def CreateClone(self):
return bhs_system_strategy()