Rabbit M2 策略
概述
Rabbit M2 是一套顺势交易策略,结合了动量震荡指标、唐奇安通道突破以及自适应仓位管理。原版 MetaTrader 5 智能交易系统由 Peter Byrom 编写,通过 1 小时时间框架上的指数移动平均线 (EMA) 切换做多或做空模式。在允许的方向下,策略等待威廉指标 (%R) 穿越关键阈值,并使用商品通道指数 (CCI) 进行确认后才开仓。每笔交易都设置固定距离的止损和止盈,当价格突破相反方向的唐奇安通道边界时也会立即平仓。若一次平仓收益超过预设的盈利阈值,基础下单手数会按步长增加,同时盈利阈值翻倍,从而复刻原策略的递进加仓逻辑。
指标与行情
- 快速 EMA (40) 与慢速 EMA (80):基于 1 小时 K 线,用于判定趋势并在趋势反转时关闭仓位。
- CCI (14):使用主时间框架的价格数据,确认市场是否处于超买或超卖状态。
- Williams %R (50):同样基于主时间框架,当指标穿越 -20/-80 水平时给出触发信号。
- 唐奇安通道 (100):基于主时间框架计算,若价格突破过去 100 根 K 线的最高或最低,触发强制平仓。
- 固定止损与止盈:距离开仓价 50 点 (根据 3/5 位报价自动换算为标准点值)。
策略需要两路行情:主时间框架用于 CCI、Williams %R 与唐奇安通道,另一路为 1 小时行情供 EMA 趋势过滤使用。
交易规则
趋势控制
- 当 40 周期 EMA 跌破 80 周期 EMA 时,立即平掉所有多单,并且仅允许寻找做空机会。
- 当 40 周期 EMA 上穿 80 周期 EMA 时,立即平掉所有空单,并且仅允许寻找做多机会。
入场条件
- 做空
- Williams %R 跌破 -20,且上一根数值位于 -20 与 0 之间。
- CCI 高于卖出阈值 (默认 101)。
- 当前处于允许做空的模式,且净头寸未达到
MaxOpenPositions限制。
- 做多
- Williams %R 上穿 -80,且上一根数值位于 -100 与 -80 之间。
- CCI 低于买入阈值 (默认 99)。
- 当前处于允许做多的模式,且净头寸未达到
MaxOpenPositions限制。
每次信号触发时,策略会先平掉反向持仓,再按照当前基础手数建立新仓位。
出场条件
- 每根完成的 K 线都会检查止损与止盈:多单若最低价跌破止损或最高价触及止盈则平仓,空单规则相反。
- 无论是否命中止损/止盈,只要价格收盘突破前 100 根 K 线的最高点(空单)或最低点(多单),立即平仓。
- 趋势方向翻转(快 EMA 与慢 EMA 金叉/死叉)时,无条件清空持仓。
仓位管理
- 基础下单量由
InitialVolume(默认 0.01) 指定,并会自动遵循交易所的最小手数、步长与上限要求。 - 每当一次平仓的实际盈利大于
BigWinTarget,基础下单量增加VolumeStep,同时盈利阈值翻倍,形成阶梯式放大利润的效果。 MaxOpenPositions控制净持仓倍数。在 StockSharp 版本中采用净持仓模式,达到上限前不会再追加仓位。
参数
| 名称 | 默认值 | 说明 |
|---|---|---|
CciSellLevel |
101 | 触发做空前 CCI 必须达到的最小数值。 |
CciBuyLevel |
99 | 触发做多前 CCI 允许的最大数值。 |
CciPeriod |
14 | 主时间框架上 CCI 的周期。 |
DonchianPeriod |
100 | 唐奇安通道的回溯长度。 |
MaxOpenPositions |
1 | 以基础手数计的最大允许净头寸。 |
BigWinTarget |
1.50 | 触发加仓所需的实际盈利(账户货币)。 |
VolumeStep |
0.01 | 每次达标后增加的基础手数步长。 |
WprPeriod |
50 | Williams %R 的周期。 |
FastEmaPeriod |
40 | 1 小时趋势过滤的快速 EMA 周期。 |
SlowEmaPeriod |
80 | 1 小时趋势过滤的慢速 EMA 周期。 |
TakeProfitPips |
50 | 止盈距离(点)。 |
StopLossPips |
50 | 止损距离(点)。 |
InitialVolume |
0.01 | 启动时的基础下单量。 |
CandleType |
15 分钟 K 线 | 主时间框架,供 CCI / Williams %R / 唐奇安通道计算。 |
实现说明
- StockSharp 版本通过监测 K 线高低点来模拟 MT5 的止损与止盈,而非挂出带保护的委托。
- 当标的价格精度为 3 位或 5 位小数时,会自动将最小报价步长乘以 10 来换算标准点值。
- 策略依赖成交回报更新实时盈亏 (PnL) 来判断“大赢”事件,请确保成交回报能正确回传到策略中。
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;
using StockSharp.Algo;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Rabbit M2 strategy converted from the MetaTrader 5 expert advisor.
/// Combines EMA trend gating, Williams %R momentum and adaptive position sizing.
/// </summary>
public class RabbitM2Strategy : Strategy
{
private readonly StrategyParam<int> _cciSellLevel;
private readonly StrategyParam<int> _cciBuyLevel;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<int> _donchianPeriod;
private readonly StrategyParam<int> _maxOpenPositions;
private readonly StrategyParam<decimal> _bigWinTarget;
private readonly StrategyParam<decimal> _volumeStep;
private readonly StrategyParam<int> _wprPeriod;
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<int> _takeProfitPips;
private readonly StrategyParam<int> _stopLossPips;
private readonly StrategyParam<decimal> _initialVolume;
private readonly StrategyParam<DataType> _candleType;
private decimal _tradeVolume;
private decimal _bigWinThreshold;
private decimal _stopLossDistance;
private decimal _takeProfitDistance;
private decimal? _previousWpr;
private decimal? _previousDonchianUpper;
private decimal? _previousDonchianLower;
private bool _buyAllowed;
private bool _sellAllowed;
private decimal _lastRealizedPnL;
private decimal _currentStop;
private decimal _currentTake;
/// <summary>
/// Initializes a new instance of the <see cref="RabbitM2Strategy"/> class.
/// </summary>
public RabbitM2Strategy()
{
_cciSellLevel = Param(nameof(CciSellLevel), 101)
.SetDisplay("CCI Sell Level", "CCI threshold confirming short signals", "CCI")
;
_cciBuyLevel = Param(nameof(CciBuyLevel), 99)
.SetDisplay("CCI Buy Level", "CCI threshold confirming long signals", "CCI")
;
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "Lookback for the Commodity Channel Index", "CCI")
;
_donchianPeriod = Param(nameof(DonchianPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("Donchian Period", "Lookback used for breakout exits", "Donchian")
;
_maxOpenPositions = Param(nameof(MaxOpenPositions), 1)
.SetGreaterThanZero()
.SetDisplay("Max Open Positions", "Maximum net exposure in base volume multiples", "Risk")
;
_bigWinTarget = Param(nameof(BigWinTarget), 1.50m)
.SetGreaterThanZero()
.SetDisplay("Big Win Target", "Profit needed before increasing position size", "Money Management")
;
_volumeStep = Param(nameof(VolumeStep), 0.01m)
.SetGreaterThanZero()
.SetDisplay("Volume Step", "Increment applied to the base volume after a big win", "Money Management")
;
_wprPeriod = Param(nameof(WprPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Williams %R Period", "Length of the Williams %R oscillator", "Momentum")
;
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 40)
.SetGreaterThanZero()
.SetDisplay("Fast EMA Period", "Fast EMA period on the hourly trend feed", "Trend Filter")
;
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 80)
.SetGreaterThanZero()
.SetDisplay("Slow EMA Period", "Slow EMA period on the hourly trend feed", "Trend Filter")
;
_takeProfitPips = Param(nameof(TakeProfitPips), 50)
.SetGreaterThanZero()
.SetDisplay("Take Profit (pips)", "Distance from entry to take profit", "Risk")
;
_stopLossPips = Param(nameof(StopLossPips), 50)
.SetGreaterThanZero()
.SetDisplay("Stop Loss (pips)", "Distance from entry to stop loss", "Risk")
;
_initialVolume = Param(nameof(InitialVolume), 0.01m)
.SetGreaterThanZero()
.SetDisplay("Initial Volume", "Starting base order size", "Money Management")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Primary Candle Type", "Timeframe for CCI, Williams %R and Donchian", "General");
}
/// <summary>
/// Minimum CCI value required to confirm a short setup.
/// </summary>
public int CciSellLevel
{
get => _cciSellLevel.Value;
set => _cciSellLevel.Value = value;
}
/// <summary>
/// Maximum CCI value required to confirm a long setup.
/// </summary>
public int CciBuyLevel
{
get => _cciBuyLevel.Value;
set => _cciBuyLevel.Value = value;
}
/// <summary>
/// CCI calculation period.
/// </summary>
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
/// <summary>
/// Donchian channel lookback length.
/// </summary>
public int DonchianPeriod
{
get => _donchianPeriod.Value;
set => _donchianPeriod.Value = value;
}
/// <summary>
/// Maximum number of net position multiples that can be opened.
/// </summary>
public int MaxOpenPositions
{
get => _maxOpenPositions.Value;
set => _maxOpenPositions.Value = value;
}
/// <summary>
/// Profit threshold that triggers a volume increase.
/// </summary>
public decimal BigWinTarget
{
get => _bigWinTarget.Value;
set => _bigWinTarget.Value = value;
}
/// <summary>
/// Volume increment applied after a qualifying win.
/// </summary>
public decimal VolumeStep
{
get => _volumeStep.Value;
set => _volumeStep.Value = value;
}
/// <summary>
/// Williams %R period.
/// </summary>
public int WprPeriod
{
get => _wprPeriod.Value;
set => _wprPeriod.Value = value;
}
/// <summary>
/// Fast EMA period used for the hourly trend filter.
/// </summary>
public int FastEmaPeriod
{
get => _fastEmaPeriod.Value;
set => _fastEmaPeriod.Value = value;
}
/// <summary>
/// Slow EMA period used for the hourly trend filter.
/// </summary>
public int SlowEmaPeriod
{
get => _slowEmaPeriod.Value;
set => _slowEmaPeriod.Value = value;
}
/// <summary>
/// Take profit distance expressed in pips.
/// </summary>
public int TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Stop loss distance expressed in pips.
/// </summary>
public int StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Base order size before scaling logic is applied.
/// </summary>
public decimal InitialVolume
{
get => _initialVolume.Value;
set => _initialVolume.Value = value;
}
/// <summary>
/// Primary candle type used for CCI, Williams %R and Donchian calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
yield return (Security, TimeSpan.FromHours(4).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_tradeVolume = 0m;
_bigWinThreshold = 0m;
_stopLossDistance = 0m;
_takeProfitDistance = 0m;
_previousWpr = null;
_previousDonchianUpper = null;
_previousDonchianLower = null;
_buyAllowed = false;
_sellAllowed = false;
_lastRealizedPnL = 0m;
_currentStop = 0m;
_currentTake = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_tradeVolume = InitialVolume;
_bigWinThreshold = BigWinTarget;
EnsureVolumeBoundaries();
_lastRealizedPnL = PnL;
var pipSize = GetPipSize();
_stopLossDistance = StopLossPips * pipSize;
_takeProfitDistance = TakeProfitPips * pipSize;
// Initialize indicators that operate on the primary timeframe.
var wpr = new WilliamsR { Length = WprPeriod };
var cci = new CommodityChannelIndex { Length = CciPeriod };
var donchian = new DonchianChannels { Length = DonchianPeriod };
// Initialize hourly EMA indicators for trend gating.
var emaFast = new EMA { Length = FastEmaPeriod };
var emaSlow = new EMA { Length = SlowEmaPeriod };
var trendSubscription = SubscribeCandles(TimeSpan.FromHours(4).TimeFrame());
trendSubscription
.Bind(emaFast, emaSlow, ProcessTrend)
.Start();
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(wpr, cci, donchian, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, emaFast);
DrawIndicator(area, emaSlow);
DrawOwnTrades(area);
}
}
private void ProcessTrend(ICandleMessage candle, decimal emaFast, decimal emaSlow)
{
if (candle.State != CandleStates.Finished)
return;
if (emaFast < emaSlow)
{
_sellAllowed = true;
_buyAllowed = false;
CloseLongPosition("EMA trend flipped to bearish mode");
}
else if (emaFast > emaSlow)
{
_buyAllowed = true;
_sellAllowed = false;
CloseShortPosition("EMA trend flipped to bullish mode");
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue wprValue, IIndicatorValue cciValue, IIndicatorValue donchianValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!wprValue.IsFinal || !cciValue.IsFinal || !donchianValue.IsFinal)
return;
var donchian = (DonchianChannelsValue)donchianValue;
if (donchian.UpperBand is not decimal upperBand || donchian.LowerBand is not decimal lowerBand)
return;
// Always evaluate protective exits before considering new entries.
ManageExistingPosition(candle, upperBand, lowerBand);
var wprCurrent = wprValue.ToDecimal();
var wprPrevious = _previousWpr;
var cciCurrent = cciValue.ToDecimal();
if (wprCurrent == 0m)
wprCurrent = -1m;
_previousWpr = wprCurrent;
// indicators bound via .BindEx()
if (_tradeVolume <= 0m)
return;
if (wprPrevious is null)
return;
var wprLag = wprPrevious.Value;
if (wprLag == 0m)
wprLag = -1m;
// Check for short entries when the short regime is active.
var canAddShort = Position <= 0m && Math.Abs(Position) < _tradeVolume * MaxOpenPositions;
if (_sellAllowed && canAddShort && wprCurrent < -20m && wprLag > -20m && wprLag < 0m && cciCurrent > CciSellLevel)
{
var volume = _tradeVolume + Math.Max(0m, Position);
if (volume > 0m)
{
SellMarket();
_currentStop = candle.ClosePrice + _stopLossDistance;
_currentTake = candle.ClosePrice - _takeProfitDistance;
}
return;
}
// Check for long entries when the long regime is active.
var canAddLong = Position >= 0m && Math.Abs(Position) < _tradeVolume * MaxOpenPositions;
if (_buyAllowed && canAddLong && wprCurrent > -80m && wprLag < -80m && wprLag < 0m && cciCurrent < CciBuyLevel)
{
var volume = _tradeVolume + Math.Max(0m, -Position);
if (volume > 0m)
{
BuyMarket();
_currentStop = candle.ClosePrice - _stopLossDistance;
_currentTake = candle.ClosePrice + _takeProfitDistance;
}
}
}
private void ManageExistingPosition(ICandleMessage candle, decimal currentUpper, decimal currentLower)
{
if (Position > 0m)
{
// Protect long positions with take profit, stop loss and Donchian breakout checks.
if (_currentTake > 0m && candle.HighPrice >= _currentTake)
{
CloseLongPosition("Take profit reached");
}
else if (_currentStop > 0m && candle.LowPrice <= _currentStop)
{
CloseLongPosition("Stop loss reached");
}
else if (_previousDonchianLower is decimal previousLower && candle.ClosePrice < previousLower)
{
CloseLongPosition("Donchian breakout against long position");
}
}
else if (Position < 0m)
{
// Protect short positions using the same logic mirrored for shorts.
if (_currentTake > 0m && candle.LowPrice <= _currentTake)
{
CloseShortPosition("Take profit reached");
}
else if (_currentStop > 0m && candle.HighPrice >= _currentStop)
{
CloseShortPosition("Stop loss reached");
}
else if (_previousDonchianUpper is decimal previousUpper && candle.ClosePrice > previousUpper)
{
CloseShortPosition("Donchian breakout against short position");
}
}
_previousDonchianUpper = currentUpper;
_previousDonchianLower = currentLower;
}
private void CloseLongPosition(string reason)
{
var volume = Math.Abs(Position);
if (volume <= 0m)
return;
SellMarket();
_currentStop = 0m;
_currentTake = 0m;
LogInfo($"Closing long position: {reason}.");
}
private void CloseShortPosition(string reason)
{
var volume = Math.Abs(Position);
if (volume <= 0m)
return;
BuyMarket();
_currentStop = 0m;
_currentTake = 0m;
LogInfo($"Closing short position: {reason}.");
}
/// <inheritdoc />
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
var realizedChange = PnL - _lastRealizedPnL;
_lastRealizedPnL = PnL;
// Increase the base volume after sufficiently profitable exits.
if (realizedChange > _bigWinThreshold)
{
_tradeVolume += VolumeStep;
EnsureVolumeBoundaries();
_bigWinThreshold *= 2m;
}
if (Math.Abs(Position) == 0m)
{
_currentStop = 0m;
_currentTake = 0m;
}
}
private void EnsureVolumeBoundaries()
{
var step = Security?.VolumeStep;
if (step.HasValue && step.Value > 0m)
{
var steps = Math.Floor(_tradeVolume / step.Value);
_tradeVolume = steps * step.Value;
}
var max = Security?.MaxVolume;
if (max.HasValue && max.Value > 0m && _tradeVolume > max.Value)
_tradeVolume = max.Value;
var min = Security?.MinVolume;
if (min.HasValue && min.Value > 0m && _tradeVolume < min.Value)
_tradeVolume = 0m;
Volume = _tradeVolume;
}
private decimal GetPipSize()
{
var priceStep = Security?.PriceStep ?? 0m;
if (priceStep <= 0m)
priceStep = 0.0001m;
var decimals = Security?.Decimals;
if (decimals == 3 || decimals == 5)
priceStep *= 10m;
return priceStep;
}
}
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 (
ExponentialMovingAverage, CommodityChannelIndex, WilliamsR,
Highest, Lowest
)
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class rabbit_m2_strategy(Strategy):
def __init__(self):
super(rabbit_m2_strategy, self).__init__()
self._cci_sell_level = self.Param("CciSellLevel", 101).SetDisplay("CCI Sell Level", "CCI threshold for shorts", "CCI")
self._cci_buy_level = self.Param("CciBuyLevel", 99).SetDisplay("CCI Buy Level", "CCI threshold for longs", "CCI")
self._cci_period = self.Param("CciPeriod", 14).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "CCI")
self._donchian_period = self.Param("DonchianPeriod", 100).SetGreaterThanZero().SetDisplay("Donchian Period", "Donchian lookback", "Donchian")
self._wpr_period = self.Param("WprPeriod", 50).SetGreaterThanZero().SetDisplay("Williams %R Period", "Williams %R lookback", "Momentum")
self._fast_ema_period = self.Param("FastEmaPeriod", 40).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA for trend", "Trend Filter")
self._slow_ema_period = self.Param("SlowEmaPeriod", 80).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA for trend", "Trend Filter")
self._tp_pips = self.Param("TakeProfitPips", 50).SetGreaterThanZero().SetDisplay("Take Profit (pips)", "TP distance", "Risk")
self._sl_pips = self.Param("StopLossPips", 50).SetGreaterThanZero().SetDisplay("Stop Loss (pips)", "SL distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Primary timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(rabbit_m2_strategy, self).OnReseted()
self._buy_allowed = False
self._sell_allowed = False
self._prev_wpr = None
self._prev_don_upper = None
self._prev_don_lower = None
self._current_stop = 0
self._current_take = 0
self._pip_size = 0
def OnStarted2(self, time):
super(rabbit_m2_strategy, self).OnStarted2(time)
self._buy_allowed = False
self._sell_allowed = False
self._prev_wpr = None
self._prev_don_upper = None
self._prev_don_lower = None
self._current_stop = 0
self._current_take = 0
self._pip_size = self._get_pip_size()
self._sl_dist = self._sl_pips.Value * self._pip_size
self._tp_dist = self._tp_pips.Value * self._pip_size
wpr = WilliamsR()
wpr.Length = self._wpr_period.Value
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
don_high = Highest()
don_high.Length = self._donchian_period.Value
don_low = Lowest()
don_low.Length = self._donchian_period.Value
ema_fast = ExponentialMovingAverage()
ema_fast.Length = self._fast_ema_period.Value
ema_slow = ExponentialMovingAverage()
ema_slow.Length = self._slow_ema_period.Value
trend_sub = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromHours(4)))
trend_sub.Bind(ema_fast, ema_slow, self._on_trend).Start()
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(wpr, cci, don_high, don_low, self._on_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, ema_fast)
self.DrawIndicator(area, ema_slow)
self.DrawOwnTrades(area)
def _get_pip_size(self):
step = 0.0001
if self.Security is not None and self.Security.PriceStep is not None and self.Security.PriceStep > 0:
step = float(self.Security.PriceStep)
return step
def _on_trend(self, candle, ema_fast_val, ema_slow_val):
if candle.State != CandleStates.Finished:
return
if ema_fast_val < ema_slow_val:
self._sell_allowed = True
self._buy_allowed = False
if self.Position > 0:
self.SellMarket()
self._current_stop = 0
self._current_take = 0
elif ema_fast_val > ema_slow_val:
self._buy_allowed = True
self._sell_allowed = False
if self.Position < 0:
self.BuyMarket()
self._current_stop = 0
self._current_take = 0
def _on_candle(self, candle, wpr_val, cci_val, don_high_val, don_low_val):
if candle.State != CandleStates.Finished:
return
self._manage_position(candle, don_high_val, don_low_val)
if self._prev_wpr is None:
self._prev_wpr = wpr_val
return
wpr_current = wpr_val
if wpr_current == 0:
wpr_current = -1
wpr_lag = self._prev_wpr
if wpr_lag == 0:
wpr_lag = -1
self._prev_wpr = wpr_current
close = candle.ClosePrice
if self._sell_allowed and self.Position >= 0:
if wpr_current < -20 and wpr_lag > -20 and wpr_lag < 0 and cci_val > self._cci_sell_level.Value:
self.SellMarket()
self._current_stop = close + self._sl_dist
self._current_take = close - self._tp_dist
return
if self._buy_allowed and self.Position <= 0:
if wpr_current > -80 and wpr_lag < -80 and wpr_lag < 0 and cci_val < self._cci_buy_level.Value:
self.BuyMarket()
self._current_stop = close - self._sl_dist
self._current_take = close + self._tp_dist
def _manage_position(self, candle, upper, lower):
if self.Position > 0:
if self._current_take > 0 and candle.HighPrice >= self._current_take:
self.SellMarket()
self._current_stop = 0
self._current_take = 0
elif self._current_stop > 0 and candle.LowPrice <= self._current_stop:
self.SellMarket()
self._current_stop = 0
self._current_take = 0
elif self._prev_don_lower is not None and candle.ClosePrice < self._prev_don_lower:
self.SellMarket()
self._current_stop = 0
self._current_take = 0
elif self.Position < 0:
if self._current_take > 0 and candle.LowPrice <= self._current_take:
self.BuyMarket()
self._current_stop = 0
self._current_take = 0
elif self._current_stop > 0 and candle.HighPrice >= self._current_stop:
self.BuyMarket()
self._current_stop = 0
self._current_take = 0
elif self._prev_don_upper is not None and candle.ClosePrice > self._prev_don_upper:
self.BuyMarket()
self._current_stop = 0
self._current_take = 0
self._prev_don_upper = upper
self._prev_don_lower = lower
def CreateClone(self):
return rabbit_m2_strategy()