IBS RSI CCI v4 X2戦略
概要
IBS RSI CCI v4 X2戦略は、Internal Bar Strength (IBS)、Relative Strength Index (RSI)、Commodity Channel Index (CCI)を組み合わせたマルチ時間軸モメンタムシステムです。MetaTrader 5エコシステムの元のアルゴリズムがStockSharpに移植され、インジケーターバインディングを使用した高レベルのローソク足サブスクリプションを使用するように再設計されています。2つの独立したインジケーターパイプラインが評価されます:方向バイアスを定義する低速の「トレンド」時間軸と、エントリーおよびエグジット判断を生成する高速の「シグナル」時間軸です。
各時間軸で戦略は複合オシレーターを計算します。オシレーター値はIBS、RSI、CCIの加重寄与から導出されます。複合値の急速な変化は平滑化され、設定可能なモメンタム閾値でクランプされ、元のインジケーターバッファリングロジックを模倣したボラティリティエンベロープでラップされます。複合値とその平滑化されたエンベロープ間のクロスオーバーが判断のコアトリガーです。
トレードロジック
- トレンド検出 – 低速時間軸が複合オシレーターを監視します。複合値がエンベロープより上に留まると戦略は上昇トレンドをマークし、そうでなければ下降トレンドをフラグします。
- シグナル生成 – 高速時間軸が複合値とエンベロープの2つの連続する値を評価します。最新バーのクロスオーバーは、前のバーがその移行をサポートしている場合にのみ実行可能なシグナルを確認します。
- エントリールール –
- ロングポジションが許可されており、現在のトレンドが強気で、高速時間軸で複合値がエンベロープを下方にクロスした場合(元のインジケーター方向での弱気から強気への反転)のみロングにエントリーします。
- ショートポジションが許可されており、現在のトレンドが弱気で、高速時間軸で複合値がエンベロープを上方にクロスした場合のみショートにエントリーします。
- エグジットルール –
_CloseLongOnSignalCrossまたは_CloseShortOnSignalCrossトグルが有効な場合、複合クロスオーバーでの任意の即時エグジット。- 低速時間軸のバイアスが反転するとすぐに
_CloseLongOnTrendFlipまたは_CloseShortOnTrendFlipがクローズを要求する場合の強制トレンドベースエグジット。 - リスク管理はStockSharpの
StartProtectionで処理され、設定されたポイントベースのストップロスとテイクプロフィットの距離を、インストゥルメントの価格ステップを使用して絶対価格オフセットに変換します。
インジケーターと計算
- Internal Bar Strength (IBS):
(close - low) / max(high - low, price step)を選択可能な移動平均で平滑化。 - RSI: 設定可能な適用価格(終値、始値、高値、安値、中間値、典型値、加重値)に適用された標準RSI。
- CCI: 選択された適用価格から導出された単純移動平均と平均偏差推定器を使用したカスタムCCI実装。
- 複合オシレーター: 変換されたIBS、RSI、CCI値の加重合計を3で割り、元の「モメンタムリミッター」を複製するために
Threshold設定でクランプしたもの。 - エンベロープ: 設定された範囲での最高および最低複合値を2回平滑化して平均し、クロスオーバーに使用するシグナルベースラインを生成します。
この実装は、すべての状態を計算クラス内に保持し、高レベルAPIを通じてローソク足を順次供給することで、インジケーター値の直接ポーリング(GetValue)を回避します。
パラメーター
| パラメーター | 説明 |
|---|---|
OrderVolume |
新しいポジションを開く際に使用する基本注文サイズ。 |
TrendCandleType |
低速時間軸サブスクリプションのローソク足タイプ。 |
TrendIbsPeriod, TrendIbsMaType |
低速時間軸のIBS平滑化期間と移動平均タイプ。 |
TrendRsiPeriod, TrendRsiPrice |
低速時間軸のRSI期間と適用価格。 |
TrendCciPeriod, TrendCciPrice |
低速時間軸のCCI期間と適用価格。 |
TrendThreshold |
低速時間軸の複合値で使用するモメンタムクランプ閾値。 |
TrendRangePeriod, TrendSmoothPeriod |
低速時間軸エンベロープのルックバック範囲と平滑化ウィンドウ。 |
TrendSignalBar |
低速時間軸の値を読み取る際に使用するオフセット(閉じたローソク足の数)。 |
AllowLongEntries, AllowShortEntries |
新規ロング/ショートトレードを有効または無効にする。 |
CloseLongOnTrendFlip, CloseShortOnTrendFlip |
低速時間軸のバイアスが反転するとポジションのエグジットを強制する。 |
SignalCandleType |
高速時間軸サブスクリプションのローソク足タイプ。 |
SignalIbsPeriod, SignalIbsMaType |
高速時間軸のIBS平滑化設定。 |
SignalRsiPeriod, SignalRsiPrice |
高速時間軸のRSI設定。 |
SignalCciPeriod, SignalCciPrice |
高速時間軸のCCI設定。 |
SignalThreshold |
高速時間軸の複合値で使用するモメンタムクランプ閾値。 |
SignalRangePeriod, SignalSmoothPeriod |
高速時間軸のエンベロープ範囲と平滑化。 |
SignalSignalBar |
高速時間軸シグナルを評価する際に適用するオフセット。 |
CloseLongOnSignalCross, CloseShortOnSignalCross |
高速時間軸クロスオーバーでの任意のエグジットトリガー。 |
StopLossPoints, TakeProfitPoints |
価格ステップポイントで測定したストップロスとテイクプロフィットの距離。 |
使用上の注意
- 戦略を開始する前にインストゥルメントとローソク足タイプを設定してください。両方の時間軸は
GetWorkingSecuritiesを通じて自動的にサブスクライブされます。 - デフォルト設定は元のMQLバージョンを反映しています:8時間トレンドローソク足と1時間シグナルローソク足で、両方の時間軸で同一のインジケーター設定です。
- 複合オシレーターは内部でクランプされるため、極端なボラティリティ期間は典型的なモメンタム戦略よりも平坦な反応を生成することがあります。感度を適応させるために
Threshold、RangePeriod、SmoothPeriodパラメーターを調整してください。 - 組み込みのポジション保護はインストゥルメントの
PriceStepに依存します。インストゥルメントメタデータが有効なステップを提供することを確認してください。そうでない場合はコードのフォールバックを調整することを検討してください。 - 動作を視覚化する必要がある場合はStockSharpのチャートヘルパーを使用してください。戦略はすでにチャートエリアが利用可能な場合、シグナル時間軸のローソク足と実行されたトレードを描画します。
リスクと制限
- 戦略は順次ローソク足配信を前提としています。順序外れのローソク足更新は内部バッファを非同期化する可能性があります。
- カスタムCCIの平均偏差はバッファされた値から再計算されます。精度はギャップなしの継続的なデータストリームの受信に依存します。
OrderVolumeが既存のエクスポージャーと組み合わされると、フリップは反対のポジションを閉じて新しいポジションを開くサイズの単一の成行注文を送信することで実行されます。ブローカーの権限がその動作を許可していることを確認してください。- ポートは元のインジケーターの方向(負の係数)を保持します。したがって、レガシーインジケーターの設計を確認するまでシグナルは直感に反して見える場合があります。
戦略の拡張
- エンベロープとIBS平滑化の移動平均タイプを独立して調整して、より速いまたは遅い反応を探索します。
- 将来のリリースで必要な価格セレクターが公開された場合、カスタムCCI計算機をStockSharpの組み込みインジケーターに置き換えます。
- より多くの視覚的フィードバックが必要な場合、複合値を追加のチャートペインにバインドしてチャートオーバーレイを追加します。
- 本番環境への展開のために、最大日次損失やトレード時間フィルターなどの追加リスク制御と組み合わせます。
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;
public class IbsRsiCciV4X2Strategy : Strategy
{
private readonly StrategyParam<decimal> _orderVolume;
private readonly StrategyParam<DataType> _trendCandleType;
private readonly StrategyParam<int> _trendIbsPeriod;
private readonly StrategyParam<IbsMovingAverageTypes> _trendIbsMaType;
private readonly StrategyParam<int> _trendRsiPeriod;
private readonly StrategyParam<AppliedPriceTypes> _trendRsiPrice;
private readonly StrategyParam<int> _trendCciPeriod;
private readonly StrategyParam<AppliedPriceTypes> _trendCciPrice;
private readonly StrategyParam<decimal> _trendThreshold;
private readonly StrategyParam<int> _trendRangePeriod;
private readonly StrategyParam<int> _trendSmoothPeriod;
private readonly StrategyParam<int> _trendSignalBar;
private readonly StrategyParam<bool> _allowLongEntries;
private readonly StrategyParam<bool> _allowShortEntries;
private readonly StrategyParam<bool> _closeLongOnTrendFlip;
private readonly StrategyParam<bool> _closeShortOnTrendFlip;
private readonly StrategyParam<decimal> _koefIbs;
private readonly StrategyParam<decimal> _koefRsi;
private readonly StrategyParam<decimal> _koefCci;
private readonly StrategyParam<decimal> _kibs;
private readonly StrategyParam<decimal> _kcci;
private readonly StrategyParam<decimal> _krsi;
private readonly StrategyParam<decimal> _posit;
private readonly StrategyParam<DataType> _signalCandleType;
private readonly StrategyParam<int> _signalIbsPeriod;
private readonly StrategyParam<IbsMovingAverageTypes> _signalIbsMaType;
private readonly StrategyParam<int> _signalRsiPeriod;
private readonly StrategyParam<AppliedPriceTypes> _signalRsiPrice;
private readonly StrategyParam<int> _signalCciPeriod;
private readonly StrategyParam<AppliedPriceTypes> _signalCciPrice;
private readonly StrategyParam<decimal> _signalThreshold;
private readonly StrategyParam<int> _signalRangePeriod;
private readonly StrategyParam<int> _signalSmoothPeriod;
private readonly StrategyParam<int> _signalSignalBar;
private readonly StrategyParam<int> _signalCooldownBars;
private readonly StrategyParam<bool> _closeLongOnSignalCross;
private readonly StrategyParam<bool> _closeShortOnSignalCross;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private readonly List<IbsRsiCciValue> _trendValues = new();
private readonly List<IbsRsiCciValue> _signalValues = new();
private IbsRsiCciCalculator _trendCalculator;
private IbsRsiCciCalculator _signalCalculator;
private int _trendDirection;
private int _cooldownRemaining;
public IbsRsiCciV4X2Strategy()
{
_orderVolume = Param(nameof(OrderVolume), 1m)
.SetGreaterThanZero()
.SetDisplay("Volume", "Order volume", "Trading");
_trendCandleType = Param(nameof(TrendCandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Trend TF", "Trend timeframe", "Trend");
_trendIbsPeriod = Param(nameof(TrendIbsPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Trend IBS", "IBS smoothing period", "Trend");
_trendIbsMaType = Param(nameof(TrendIbsMaType), IbsMovingAverageTypes.Simple)
.SetDisplay("Trend IBS MA", "IBS smoothing type", "Trend");
_trendRsiPeriod = Param(nameof(TrendRsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Trend RSI", "RSI period", "Trend");
_trendRsiPrice = Param(nameof(TrendRsiPrice), AppliedPriceTypes.Close)
.SetDisplay("Trend RSI Price", "RSI price type", "Trend");
_trendCciPeriod = Param(nameof(TrendCciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Trend CCI", "CCI period", "Trend");
_trendCciPrice = Param(nameof(TrendCciPrice), AppliedPriceTypes.Median)
.SetDisplay("Trend CCI Price", "CCI price type", "Trend");
_trendThreshold = Param(nameof(TrendThreshold), 50m)
.SetGreaterThanZero()
.SetDisplay("Trend Threshold", "Momentum clamp threshold", "Trend");
_trendRangePeriod = Param(nameof(TrendRangePeriod), 25)
.SetGreaterThanZero()
.SetDisplay("Trend Range", "Range period", "Trend");
_trendSmoothPeriod = Param(nameof(TrendSmoothPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Trend Smooth", "Range smoothing period", "Trend");
_trendSignalBar = Param(nameof(TrendSignalBar), 1)
.SetNotNegative()
.SetDisplay("Trend Shift", "Shift used to read indicator", "Trend");
_allowLongEntries = Param(nameof(AllowLongEntries), true)
.SetDisplay("Allow Long", "Enable long entries", "Trading");
_allowShortEntries = Param(nameof(AllowShortEntries), true)
.SetDisplay("Allow Short", "Enable short entries", "Trading");
_closeLongOnTrendFlip = Param(nameof(CloseLongOnTrendFlip), true)
.SetDisplay("Close Long Trend", "Close longs on bearish trend", "Trading");
_closeShortOnTrendFlip = Param(nameof(CloseShortOnTrendFlip), true)
.SetDisplay("Close Short Trend", "Close shorts on bullish trend", "Trading");
_koefIbs = Param(nameof(KoefIbs), 7m)
.SetDisplay("IBS Weight", "Weight applied to the IBS component", "Weights")
;
_koefRsi = Param(nameof(KoefRsi), 9m)
.SetDisplay("RSI Weight", "Weight applied to the RSI component", "Weights")
;
_koefCci = Param(nameof(KoefCci), 1m)
.SetDisplay("CCI Weight", "Weight applied to the CCI component", "Weights")
;
_kibs = Param(nameof(Kibs), -1m)
.SetDisplay("IBS Direction", "Directional multiplier for the IBS input", "Weights")
;
_kcci = Param(nameof(Kcci), -1m)
.SetDisplay("CCI Direction", "Directional multiplier for the CCI input", "Weights")
;
_krsi = Param(nameof(Krsi), -1m)
.SetDisplay("RSI Direction", "Directional multiplier for the RSI input", "Weights")
;
_posit = Param(nameof(Posit), -1m)
.SetDisplay("Output Direction", "Directional multiplier for the composite output", "Weights")
;
_signalCandleType = Param(nameof(SignalCandleType), TimeSpan.FromHours(2).TimeFrame())
.SetDisplay("Signal TF", "Signal timeframe", "Signal");
_signalIbsPeriod = Param(nameof(SignalIbsPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Signal IBS", "IBS smoothing period", "Signal");
_signalIbsMaType = Param(nameof(SignalIbsMaType), IbsMovingAverageTypes.Simple)
.SetDisplay("Signal IBS MA", "IBS smoothing type", "Signal");
_signalRsiPeriod = Param(nameof(SignalRsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Signal RSI", "RSI period", "Signal");
_signalRsiPrice = Param(nameof(SignalRsiPrice), AppliedPriceTypes.Close)
.SetDisplay("Signal RSI Price", "RSI price type", "Signal");
_signalCciPeriod = Param(nameof(SignalCciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Signal CCI", "CCI period", "Signal");
_signalCciPrice = Param(nameof(SignalCciPrice), AppliedPriceTypes.Median)
.SetDisplay("Signal CCI Price", "CCI price type", "Signal");
_signalThreshold = Param(nameof(SignalThreshold), 50m)
.SetGreaterThanZero()
.SetDisplay("Signal Threshold", "Momentum clamp threshold", "Signal");
_signalRangePeriod = Param(nameof(SignalRangePeriod), 25)
.SetGreaterThanZero()
.SetDisplay("Signal Range", "Range period", "Signal");
_signalSmoothPeriod = Param(nameof(SignalSmoothPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Signal Smooth", "Range smoothing period", "Signal");
_signalSignalBar = Param(nameof(SignalSignalBar), 1)
.SetNotNegative()
.SetDisplay("Signal Shift", "Shift used to read indicator", "Signal");
_signalCooldownBars = Param(nameof(SignalCooldownBars), 10)
.SetNotNegative()
.SetDisplay("Signal Cooldown", "Closed signal candles to wait before the next entry", "Signal");
_closeLongOnSignalCross = Param(nameof(CloseLongOnSignalCross), false)
.SetDisplay("Close Long Signal", "Close longs on bearish cross", "Signal");
_closeShortOnSignalCross = Param(nameof(CloseShortOnSignalCross), false)
.SetDisplay("Close Short Signal", "Close shorts on bullish cross", "Signal");
_stopLossPoints = Param(nameof(StopLossPoints), 1000)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop loss in points", "Protection");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 2000)
.SetNotNegative()
.SetDisplay("Take Profit", "Take profit in points", "Protection");
}
public decimal OrderVolume
{
get => _orderVolume.Value;
set => _orderVolume.Value = value;
}
public DataType TrendCandleType
{
get => _trendCandleType.Value;
set => _trendCandleType.Value = value;
}
public int TrendIbsPeriod
{
get => _trendIbsPeriod.Value;
set => _trendIbsPeriod.Value = value;
}
public IbsMovingAverageTypes TrendIbsMaType
{
get => _trendIbsMaType.Value;
set => _trendIbsMaType.Value = value;
}
public int TrendRsiPeriod
{
get => _trendRsiPeriod.Value;
set => _trendRsiPeriod.Value = value;
}
public AppliedPriceTypes TrendRsiPrice
{
get => _trendRsiPrice.Value;
set => _trendRsiPrice.Value = value;
}
public int TrendCciPeriod
{
get => _trendCciPeriod.Value;
set => _trendCciPeriod.Value = value;
}
public AppliedPriceTypes TrendCciPrice
{
get => _trendCciPrice.Value;
set => _trendCciPrice.Value = value;
}
public decimal TrendThreshold
{
get => _trendThreshold.Value;
set => _trendThreshold.Value = value;
}
public int TrendRangePeriod
{
get => _trendRangePeriod.Value;
set => _trendRangePeriod.Value = value;
}
public int TrendSmoothPeriod
{
get => _trendSmoothPeriod.Value;
set => _trendSmoothPeriod.Value = value;
}
public int TrendSignalBar
{
get => _trendSignalBar.Value;
set => _trendSignalBar.Value = value;
}
public bool AllowLongEntries
{
get => _allowLongEntries.Value;
set => _allowLongEntries.Value = value;
}
public bool AllowShortEntries
{
get => _allowShortEntries.Value;
set => _allowShortEntries.Value = value;
}
public bool CloseLongOnTrendFlip
{
get => _closeLongOnTrendFlip.Value;
set => _closeLongOnTrendFlip.Value = value;
}
public bool CloseShortOnTrendFlip
{
get => _closeShortOnTrendFlip.Value;
set => _closeShortOnTrendFlip.Value = value;
}
public DataType SignalCandleType
{
get => _signalCandleType.Value;
set => _signalCandleType.Value = value;
}
public int SignalIbsPeriod
{
get => _signalIbsPeriod.Value;
set => _signalIbsPeriod.Value = value;
}
public IbsMovingAverageTypes SignalIbsMaType
{
get => _signalIbsMaType.Value;
set => _signalIbsMaType.Value = value;
}
public int SignalRsiPeriod
{
get => _signalRsiPeriod.Value;
set => _signalRsiPeriod.Value = value;
}
public AppliedPriceTypes SignalRsiPrice
{
get => _signalRsiPrice.Value;
set => _signalRsiPrice.Value = value;
}
public int SignalCciPeriod
{
get => _signalCciPeriod.Value;
set => _signalCciPeriod.Value = value;
}
public AppliedPriceTypes SignalCciPrice
{
get => _signalCciPrice.Value;
set => _signalCciPrice.Value = value;
}
public decimal SignalThreshold
{
get => _signalThreshold.Value;
set => _signalThreshold.Value = value;
}
public int SignalRangePeriod
{
get => _signalRangePeriod.Value;
set => _signalRangePeriod.Value = value;
}
public int SignalSmoothPeriod
{
get => _signalSmoothPeriod.Value;
set => _signalSmoothPeriod.Value = value;
}
public int SignalSignalBar
{
get => _signalSignalBar.Value;
set => _signalSignalBar.Value = value;
}
public bool CloseLongOnSignalCross
{
get => _closeLongOnSignalCross.Value;
set => _closeLongOnSignalCross.Value = value;
}
public bool CloseShortOnSignalCross
{
get => _closeShortOnSignalCross.Value;
set => _closeShortOnSignalCross.Value = value;
}
public int SignalCooldownBars
{
get => _signalCooldownBars.Value;
set => _signalCooldownBars.Value = value;
}
/// <summary>
/// Weight applied to the IBS component of the composite oscillator.
/// </summary>
public decimal KoefIbs
{
get => _koefIbs.Value;
set => _koefIbs.Value = value;
}
/// <summary>
/// Weight applied to the RSI component of the composite oscillator.
/// </summary>
public decimal KoefRsi
{
get => _koefRsi.Value;
set => _koefRsi.Value = value;
}
/// <summary>
/// Weight applied to the CCI component of the composite oscillator.
/// </summary>
public decimal KoefCci
{
get => _koefCci.Value;
set => _koefCci.Value = value;
}
/// <summary>
/// Directional multiplier applied to the IBS contribution.
/// </summary>
public decimal Kibs
{
get => _kibs.Value;
set => _kibs.Value = value;
}
/// <summary>
/// Directional multiplier applied to the CCI contribution.
/// </summary>
public decimal Kcci
{
get => _kcci.Value;
set => _kcci.Value = value;
}
/// <summary>
/// Directional multiplier applied to the RSI contribution.
/// </summary>
public decimal Krsi
{
get => _krsi.Value;
set => _krsi.Value = value;
}
/// <summary>
/// Directional multiplier applied to the final composite value.
/// </summary>
public decimal Posit
{
get => _posit.Value;
set => _posit.Value = value;
}
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> new[]
{
(Security, TrendCandleType),
(Security, SignalCandleType)
};
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_trendValues.Clear();
_signalValues.Clear();
_trendDirection = 0;
_cooldownRemaining = 0;
_trendCalculator?.Reset();
_signalCalculator?.Reset();
_trendCalculator = null;
_signalCalculator = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var priceStep = Security?.PriceStep ?? 0.0001m;
_trendCalculator = new IbsRsiCciCalculator(
TrendIbsPeriod,
TrendIbsMaType,
TrendRsiPeriod,
TrendRsiPrice,
TrendCciPeriod,
TrendCciPrice,
TrendThreshold,
TrendRangePeriod,
TrendSmoothPeriod,
priceStep, KoefIbs, KoefRsi, KoefCci, Kibs, Kcci, Krsi, Posit);
_signalCalculator = new IbsRsiCciCalculator(
SignalIbsPeriod,
SignalIbsMaType,
SignalRsiPeriod,
SignalRsiPrice,
SignalCciPeriod,
SignalCciPrice,
SignalThreshold,
SignalRangePeriod,
SignalSmoothPeriod,
priceStep, KoefIbs, KoefRsi, KoefCci, Kibs, Kcci, Krsi, Posit);
var trendSubscription = SubscribeCandles(TrendCandleType);
trendSubscription.Bind(ProcessTrend).Start();
var signalSubscription = SubscribeCandles(SignalCandleType);
signalSubscription.Bind(ProcessSignal).Start();
if (TakeProfitPoints > 0 || StopLossPoints > 0)
{
var takeProfit = new Unit(TakeProfitPoints * priceStep, UnitTypes.Absolute);
var stopLoss = new Unit(StopLossPoints * priceStep, UnitTypes.Absolute);
StartProtection(stopLoss, takeProfit);
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, signalSubscription);
DrawOwnTrades(area);
}
}
private void ProcessTrend(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished || _trendCalculator == null)
return;
var value = _trendCalculator.Process(candle);
if (value == null)
return;
_trendValues.Add(value.Value);
var maxCount = Math.Max(TrendSignalBar + 5, 32);
if (_trendValues.Count > maxCount)
_trendValues.RemoveAt(0);
if (_trendValues.Count <= TrendSignalBar)
return;
var index = _trendValues.Count - (TrendSignalBar + 1);
if (index < 0)
return;
var selected = _trendValues[index];
if (selected.Up > selected.Down)
_trendDirection = 1;
else if (selected.Up < selected.Down)
_trendDirection = -1;
else
_trendDirection = 0;
}
private void ProcessSignal(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished || _signalCalculator == null)
return;
if (_cooldownRemaining > 0)
_cooldownRemaining--;
var value = _signalCalculator.Process(candle);
if (value == null)
return;
_signalValues.Add(value.Value);
var maxCount = Math.Max(SignalSignalBar + 10, 48);
if (_signalValues.Count > maxCount)
_signalValues.RemoveAt(0);
if (_signalValues.Count <= SignalSignalBar + 1)
return;
var currentIndex = _signalValues.Count - (SignalSignalBar + 1);
var previousIndex = currentIndex - 1;
if (currentIndex < 0 || previousIndex < 0)
return;
var current = _signalValues[currentIndex];
var previous = _signalValues[previousIndex];
var closeLong = CloseLongOnSignalCross && previous.Up < previous.Down;
var closeShort = CloseShortOnSignalCross && previous.Up > previous.Down;
var openLong = false;
var openShort = false;
if (_trendDirection < 0)
{
if (CloseLongOnTrendFlip)
closeLong = true;
if (_cooldownRemaining == 0 && AllowShortEntries && current.Up >= current.Down && previous.Up < previous.Down)
openShort = true;
}
else if (_trendDirection > 0)
{
if (CloseShortOnTrendFlip)
closeShort = true;
if (_cooldownRemaining == 0 && AllowLongEntries && current.Up <= current.Down && previous.Up > previous.Down)
openLong = true;
}
var submitted = false;
if (closeLong && Position > 0)
{
CloseLong();
submitted = true;
}
if (closeShort && Position < 0)
{
CloseShort();
submitted = true;
}
if (openLong && Position <= 0 && AllowLongEntries)
{
EnterLong();
submitted = true;
}
else if (openShort && Position >= 0 && AllowShortEntries)
{
EnterShort();
submitted = true;
}
if (submitted)
_cooldownRemaining = SignalCooldownBars;
}
private void CloseLong()
{
if (Position <= 0)
return;
SellMarket();
}
private void CloseShort()
{
if (Position >= 0)
return;
BuyMarket();
}
private void EnterLong()
{
BuyMarket();
}
private void EnterShort()
{
SellMarket();
}
private readonly record struct IbsRsiCciValue(decimal Up, decimal Down);
private sealed class IbsRsiCciCalculator
{
private readonly decimal _koefIbs;
private readonly decimal _koefRsi;
private readonly decimal _koefCci;
private readonly decimal _kibs;
private readonly decimal _kcci;
private readonly decimal _krsi;
private readonly decimal _posit;
private readonly int _ibsPeriod;
private readonly AppliedPriceTypes _rsiPrice;
private readonly AppliedPriceTypes _cciPrice;
private readonly decimal _threshold;
private readonly decimal _priceStep;
private readonly DecimalLengthIndicator _ibsMa;
private readonly RelativeStrengthIndex _rsi;
private readonly CommodityChannelIndexCalculator _cci;
private readonly Highest _highest;
private readonly Lowest _lowest;
private readonly DecimalLengthIndicator _rangeHighMa;
private readonly DecimalLengthIndicator _rangeLowMa;
private decimal? _previousUp;
public IbsRsiCciCalculator(
int ibsPeriod,
IbsMovingAverageTypes ibsType,
int rsiPeriod,
AppliedPriceTypes rsiPrice,
int cciPeriod,
AppliedPriceTypes cciPrice,
decimal threshold,
int rangePeriod,
int smoothPeriod,
decimal priceStep,
decimal koefIbs,
decimal koefRsi,
decimal koefCci,
decimal kibs,
decimal kcci,
decimal krsi,
decimal posit)
{
_ibsPeriod = ibsPeriod;
_rsiPrice = rsiPrice;
_cciPrice = cciPrice;
_threshold = threshold;
_priceStep = priceStep;
_koefIbs = koefIbs;
_koefRsi = koefRsi;
_koefCci = koefCci;
_kibs = kibs;
_kcci = kcci;
_krsi = krsi;
_posit = posit;
_ibsMa = CreateMovingAverage(ibsType, ibsPeriod);
_rsi = new RelativeStrengthIndex { Length = rsiPeriod };
_cci = new CommodityChannelIndexCalculator(cciPeriod);
_highest = new Highest { Length = rangePeriod };
_lowest = new Lowest { Length = rangePeriod };
_rangeHighMa = CreateMovingAverage(IbsMovingAverageTypes.Smoothed, smoothPeriod);
_rangeLowMa = CreateMovingAverage(IbsMovingAverageTypes.Smoothed, smoothPeriod);
}
public IbsRsiCciValue? Process(ICandleMessage candle)
{
var range = Math.Abs(candle.HighPrice - candle.LowPrice);
if (range == 0m)
range = _priceStep;
if (range == 0m)
return null;
var ibsRaw = (candle.ClosePrice - candle.LowPrice) / range;
var ibsValue = _ibsMa.Process(new DecimalIndicatorValue(_ibsMa, ibsRaw, candle.OpenTime) { IsFinal = true });
if (!ibsValue.IsFinal)
return null;
var rsiInput = GetPrice(candle, _rsiPrice);
var rsiValue = _rsi.Process(new DecimalIndicatorValue(_rsi, rsiInput, candle.OpenTime) { IsFinal = true });
if (!rsiValue.IsFinal)
return null;
var cciInput = GetPrice(candle, _cciPrice);
var cciValue = _cci.Process(cciInput, candle.OpenTime, true);
if (cciValue == null)
return null;
var ibs = ibsValue.GetValue<decimal>();
var rsi = rsiValue.GetValue<decimal>();
var cci = cciValue.Value;
var sum = 0m;
sum += _kibs * (ibs - 0.5m) * 100m * _koefIbs;
sum += _kcci * cci * _koefCci;
sum += _krsi * (rsi - 50m) * _koefRsi;
sum /= 3m;
var target = _posit * sum;
var up = _previousUp ?? target;
var diff = target - up;
if (Math.Abs(diff) > _threshold)
{
if (diff > 0m)
up = target - _threshold;
else
up = target + _threshold;
}
else
{
up = target;
}
_previousUp = up;
var highestValue = _highest.Process(new DecimalIndicatorValue(_highest, up, candle.OpenTime) { IsFinal = true });
var lowestValue = _lowest.Process(new DecimalIndicatorValue(_lowest, up, candle.OpenTime) { IsFinal = true });
if (!highestValue.IsFinal || !lowestValue.IsFinal)
return null;
var highest = highestValue.GetValue<decimal>();
var lowest = lowestValue.GetValue<decimal>();
var highSmooth = _rangeHighMa.Process(new DecimalIndicatorValue(_rangeHighMa, highest, candle.OpenTime) { IsFinal = true });
var lowSmooth = _rangeLowMa.Process(new DecimalIndicatorValue(_rangeLowMa, lowest, candle.OpenTime) { IsFinal = true });
if (!highSmooth.IsFinal || !lowSmooth.IsFinal)
return null;
var upBand = highSmooth.GetValue<decimal>();
var lowBand = lowSmooth.GetValue<decimal>();
var signal = (upBand + lowBand) / 2m;
return new IbsRsiCciValue(up, signal);
}
public void Reset()
{
_previousUp = null;
_ibsMa.Reset();
_rsi.Reset();
_cci.Reset();
_highest.Reset();
_lowest.Reset();
_rangeHighMa.Reset();
_rangeLowMa.Reset();
}
private static DecimalLengthIndicator CreateMovingAverage(IbsMovingAverageTypes type, int length)
{
return type switch
{
IbsMovingAverageTypes.Simple => new SMA { Length = length },
IbsMovingAverageTypes.Exponential => new EMA { Length = length },
IbsMovingAverageTypes.Weighted => new WeightedMovingAverage { Length = length },
IbsMovingAverageTypes.Smoothed => new SmoothedMovingAverage { Length = length },
_ => new SMA { Length = length }
};
}
private static decimal GetPrice(ICandleMessage candle, AppliedPriceTypes type)
{
return type switch
{
AppliedPriceTypes.Close => candle.ClosePrice,
AppliedPriceTypes.Open => candle.OpenPrice,
AppliedPriceTypes.High => candle.HighPrice,
AppliedPriceTypes.Low => candle.LowPrice,
AppliedPriceTypes.Median => (candle.HighPrice + candle.LowPrice) / 2m,
AppliedPriceTypes.Typical => (candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 3m,
AppliedPriceTypes.Weighted => (candle.HighPrice + candle.LowPrice + candle.ClosePrice + candle.ClosePrice) / 4m,
_ => candle.ClosePrice
};
}
}
public enum IbsMovingAverageTypes
{
Simple,
Exponential,
Smoothed,
Weighted
}
public enum AppliedPriceTypes
{
Close,
Open,
High,
Low,
Median,
Typical,
Weighted
}
private sealed class CommodityChannelIndexCalculator
{
private readonly int _period;
private readonly SimpleMovingAverage _sma;
private readonly Queue<decimal> _buffer = new();
private readonly object _sync = new();
public CommodityChannelIndexCalculator(int period)
{
_period = period;
_sma = new SMA { Length = period };
}
public decimal? Process(decimal price, DateTimeOffset time, bool isFinal)
{
lock (_sync)
{
var maValue = _sma.Process(new DecimalIndicatorValue(_sma, price, time.UtcDateTime) { IsFinal = true });
_buffer.Enqueue(price);
if (_buffer.Count > _period)
_buffer.Dequeue();
if (!maValue.IsFinal || _buffer.Count < _period)
return null;
var ma = maValue.GetValue<decimal>();
var snapshot = _buffer.ToArray();
decimal sum = 0m;
foreach (var value in snapshot)
sum += Math.Abs(value - ma);
if (sum == 0m)
return 0m;
var meanDeviation = sum / _period;
if (meanDeviation == 0m)
return 0m;
var cci = (price - ma) / (0.015m * meanDeviation);
return cci;
}
}
public void Reset()
{
lock (_sync)
{
_buffer.Clear();
_sma.Reset();
}
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.BusinessEntities")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import (
RelativeStrengthIndex, SimpleMovingAverage,
ExponentialMovingAverage, SmoothedMovingAverage, WeightedMovingAverage,
Highest, Lowest)
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
IBS_MA_SIMPLE = 0
IBS_MA_EXPONENTIAL = 1
IBS_MA_SMOOTHED = 2
IBS_MA_WEIGHTED = 3
APPLIED_CLOSE = 0
APPLIED_OPEN = 1
APPLIED_HIGH = 2
APPLIED_LOW = 3
APPLIED_MEDIAN = 4
APPLIED_TYPICAL = 5
APPLIED_WEIGHTED = 6
class IbsRsiCciCalculator(object):
def __init__(self, ibs_period, ibs_type, rsi_period, rsi_price, cci_period, cci_price,
threshold, range_period, smooth_period, price_step,
koef_ibs, koef_rsi, koef_cci, kibs, kcci, krsi, posit):
self._rsi_price = rsi_price
self._cci_price = cci_price
self._threshold = Decimal(float(threshold))
self._price_step = Decimal(float(price_step))
self._koef_ibs = Decimal(float(koef_ibs))
self._koef_rsi = Decimal(float(koef_rsi))
self._koef_cci = Decimal(float(koef_cci))
self._kibs = Decimal(float(kibs))
self._kcci = Decimal(float(kcci))
self._krsi = Decimal(float(krsi))
self._posit = Decimal(float(posit))
self._previous_up = None
self._ibs_ma = self._create_ma(ibs_type, ibs_period)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = rsi_period
self._cci_sma = SimpleMovingAverage()
self._cci_sma.Length = cci_period
self._cci_period = cci_period
self._cci_buffer = []
self._highest = Highest()
self._highest.Length = range_period
self._lowest = Lowest()
self._lowest.Length = range_period
self._range_high_ma = self._create_ma(IBS_MA_SMOOTHED, smooth_period)
self._range_low_ma = self._create_ma(IBS_MA_SMOOTHED, smooth_period)
def _create_ma(self, ma_type, length):
t = int(ma_type)
if t == IBS_MA_EXPONENTIAL:
ind = ExponentialMovingAverage()
elif t == IBS_MA_SMOOTHED:
ind = SmoothedMovingAverage()
elif t == IBS_MA_WEIGHTED:
ind = WeightedMovingAverage()
else:
ind = SimpleMovingAverage()
ind.Length = length
return ind
def _get_price(self, candle, price_type):
h = candle.HighPrice
l = candle.LowPrice
c = candle.ClosePrice
o = candle.OpenPrice
t = int(price_type)
if t == APPLIED_OPEN:
return o
elif t == APPLIED_HIGH:
return h
elif t == APPLIED_LOW:
return l
elif t == APPLIED_MEDIAN:
return Decimal.Divide(Decimal.Add(h, l), Decimal(2))
elif t == APPLIED_TYPICAL:
return Decimal.Divide(Decimal.Add(Decimal.Add(h, l), c), Decimal(3))
elif t == APPLIED_WEIGHTED:
return Decimal.Divide(Decimal.Add(Decimal.Add(Decimal.Add(h, l), c), c), Decimal(4))
else:
return c
def process(self, candle):
h = candle.HighPrice
l = candle.LowPrice
c = candle.ClosePrice
open_time = candle.OpenTime
bar_range = Math.Abs(Decimal.Subtract(h, l))
if bar_range == Decimal(0):
bar_range = self._price_step
if bar_range == Decimal(0):
return None
ibs_raw = Decimal.Divide(Decimal.Subtract(c, l), bar_range)
ibs_result = process_float(self._ibs_ma, ibs_raw, open_time, True)
if not ibs_result.IsFinal:
return None
rsi_input = self._get_price(candle, self._rsi_price)
rsi_result = process_float(self._rsi, rsi_input, open_time, True)
if not rsi_result.IsFinal:
return None
cci_input = self._get_price(candle, self._cci_price)
cci_value = self._process_cci(cci_input, open_time)
if cci_value is None:
return None
ibs = Decimal(float(ibs_result))
rsi = Decimal(float(rsi_result))
cci = cci_value
total = Decimal(0)
# sum += _kibs * (ibs - 0.5) * 100 * _koefIbs
total = Decimal.Add(total, Decimal.Multiply(Decimal.Multiply(Decimal.Multiply(self._kibs, Decimal.Subtract(ibs, Decimal(0.5))), Decimal(100)), self._koef_ibs))
# sum += _kcci * cci * _koefCci
total = Decimal.Add(total, Decimal.Multiply(Decimal.Multiply(self._kcci, cci), self._koef_cci))
# sum += _krsi * (rsi - 50) * _koefRsi
total = Decimal.Add(total, Decimal.Multiply(Decimal.Multiply(self._krsi, Decimal.Subtract(rsi, Decimal(50))), self._koef_rsi))
# sum /= 3
total = Decimal.Divide(total, Decimal(3))
target = Decimal.Multiply(self._posit, total)
up = self._previous_up if self._previous_up is not None else target
diff = Decimal.Subtract(target, up)
if Math.Abs(diff) > self._threshold:
if diff > Decimal(0):
up = Decimal.Subtract(target, self._threshold)
else:
up = Decimal.Add(target, self._threshold)
else:
up = target
self._previous_up = up
highest_result = process_float(self._highest, up, open_time, True)
lowest_result = process_float(self._lowest, up, open_time, True)
if not highest_result.IsFinal or not lowest_result.IsFinal:
return None
highest_val = Decimal(float(highest_result))
lowest_val = Decimal(float(lowest_result))
high_smooth = process_float(self._range_high_ma, highest_val, open_time, True)
low_smooth = process_float(self._range_low_ma, lowest_val, open_time, True)
if not high_smooth.IsFinal or not low_smooth.IsFinal:
return None
up_band = Decimal(float(high_smooth))
low_band = Decimal(float(low_smooth))
signal = Decimal.Divide(Decimal.Add(up_band, low_band), Decimal(2))
return (up, signal)
def _process_cci(self, price, open_time):
ma_result = process_float(self._cci_sma, price, open_time, True)
self._cci_buffer.append(price)
if len(self._cci_buffer) > self._cci_period:
self._cci_buffer.pop(0)
if not ma_result.IsFinal or len(self._cci_buffer) < self._cci_period:
return None
ma = Decimal(float(ma_result))
total = Decimal(0)
for v in self._cci_buffer:
total = Decimal.Add(total, Math.Abs(Decimal.Subtract(v, ma)))
if total == Decimal(0):
return Decimal(0)
mean_deviation = Decimal.Divide(total, Decimal(self._cci_period))
if mean_deviation == Decimal(0):
return Decimal(0)
return Decimal.Divide(Decimal.Subtract(price, ma), Decimal.Multiply(Decimal(0.015), mean_deviation))
def reset(self):
self._previous_up = None
self._ibs_ma.Reset()
self._rsi.Reset()
self._cci_sma.Reset()
self._cci_buffer = []
self._highest.Reset()
self._lowest.Reset()
self._range_high_ma.Reset()
self._range_low_ma.Reset()
class ibs_rsi_cci_v4_x2_strategy(Strategy):
def __init__(self):
super(ibs_rsi_cci_v4_x2_strategy, self).__init__()
self._order_volume = self.Param("OrderVolume", Decimal(1))
self._trend_candle_type = self.Param("TrendCandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._trend_ibs_period = self.Param("TrendIbsPeriod", 5)
self._trend_ibs_ma_type = self.Param("TrendIbsMaType", IBS_MA_SIMPLE)
self._trend_rsi_period = self.Param("TrendRsiPeriod", 14)
self._trend_rsi_price = self.Param("TrendRsiPrice", APPLIED_CLOSE)
self._trend_cci_period = self.Param("TrendCciPeriod", 14)
self._trend_cci_price = self.Param("TrendCciPrice", APPLIED_MEDIAN)
self._trend_threshold = self.Param("TrendThreshold", Decimal(50))
self._trend_range_period = self.Param("TrendRangePeriod", 25)
self._trend_smooth_period = self.Param("TrendSmoothPeriod", 3)
self._trend_signal_bar = self.Param("TrendSignalBar", 1)
self._allow_long_entries = self.Param("AllowLongEntries", True)
self._allow_short_entries = self.Param("AllowShortEntries", True)
self._close_long_on_trend_flip = self.Param("CloseLongOnTrendFlip", True)
self._close_short_on_trend_flip = self.Param("CloseShortOnTrendFlip", True)
self._koef_ibs = self.Param("KoefIbs", Decimal(7))
self._koef_rsi = self.Param("KoefRsi", Decimal(9))
self._koef_cci = self.Param("KoefCci", Decimal(1))
self._kibs = self.Param("Kibs", Decimal(-1))
self._kcci = self.Param("Kcci", Decimal(-1))
self._krsi = self.Param("Krsi", Decimal(-1))
self._posit = self.Param("Posit", Decimal(-1))
self._signal_candle_type = self.Param("SignalCandleType", DataType.TimeFrame(TimeSpan.FromHours(2)))
self._signal_ibs_period = self.Param("SignalIbsPeriod", 5)
self._signal_ibs_ma_type = self.Param("SignalIbsMaType", IBS_MA_SIMPLE)
self._signal_rsi_period = self.Param("SignalRsiPeriod", 14)
self._signal_rsi_price = self.Param("SignalRsiPrice", APPLIED_CLOSE)
self._signal_cci_period = self.Param("SignalCciPeriod", 14)
self._signal_cci_price = self.Param("SignalCciPrice", APPLIED_MEDIAN)
self._signal_threshold = self.Param("SignalThreshold", Decimal(50))
self._signal_range_period = self.Param("SignalRangePeriod", 25)
self._signal_smooth_period = self.Param("SignalSmoothPeriod", 3)
self._signal_signal_bar = self.Param("SignalSignalBar", 1)
self._signal_cooldown_bars = self.Param("SignalCooldownBars", 10)
self._close_long_on_signal_cross = self.Param("CloseLongOnSignalCross", False)
self._close_short_on_signal_cross = self.Param("CloseShortOnSignalCross", False)
self._stop_loss_points = self.Param("StopLossPoints", 1000)
self._take_profit_points = self.Param("TakeProfitPoints", 2000)
self._trend_values = []
self._signal_values = []
self._trend_calculator = None
self._signal_calculator = None
self._trend_direction = 0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(ibs_rsi_cci_v4_x2_strategy, self).OnStarted2(time)
price_step = self.Security.PriceStep if self.Security is not None and self.Security.PriceStep is not None else Decimal(0.0001)
self._trend_calculator = IbsRsiCciCalculator(
int(self._trend_ibs_period.Value), int(self._trend_ibs_ma_type.Value),
int(self._trend_rsi_period.Value), int(self._trend_rsi_price.Value),
int(self._trend_cci_period.Value), int(self._trend_cci_price.Value),
self._trend_threshold.Value, int(self._trend_range_period.Value), int(self._trend_smooth_period.Value),
price_step,
self._koef_ibs.Value, self._koef_rsi.Value, self._koef_cci.Value,
self._kibs.Value, self._kcci.Value, self._krsi.Value, self._posit.Value)
self._signal_calculator = IbsRsiCciCalculator(
int(self._signal_ibs_period.Value), int(self._signal_ibs_ma_type.Value),
int(self._signal_rsi_period.Value), int(self._signal_rsi_price.Value),
int(self._signal_cci_period.Value), int(self._signal_cci_price.Value),
self._signal_threshold.Value, int(self._signal_range_period.Value), int(self._signal_smooth_period.Value),
price_step,
self._koef_ibs.Value, self._koef_rsi.Value, self._koef_cci.Value,
self._kibs.Value, self._kcci.Value, self._krsi.Value, self._posit.Value)
self._trend_values = []
self._signal_values = []
self._trend_direction = 0
self._cooldown_remaining = 0
trend_sub = self.SubscribeCandles(self._trend_candle_type.Value)
trend_sub.Bind(self._process_trend).Start()
signal_sub = self.SubscribeCandles(self._signal_candle_type.Value)
signal_sub.Bind(self._process_signal).Start()
tp = int(self._take_profit_points.Value)
sl = int(self._stop_loss_points.Value)
if tp > 0 or sl > 0:
take_unit = Unit(Decimal.Multiply(Decimal(tp), price_step), UnitTypes.Absolute)
stop_unit = Unit(Decimal.Multiply(Decimal(sl), price_step), UnitTypes.Absolute)
self.StartProtection(stop_unit, take_unit)
def _process_trend(self, candle):
if candle.State != CandleStates.Finished:
return
if self._trend_calculator is None:
return
value = self._trend_calculator.process(candle)
if value is None:
return
self._trend_values.append(value)
tsb = int(self._trend_signal_bar.Value)
max_count = max(tsb + 5, 32)
if len(self._trend_values) > max_count:
self._trend_values.pop(0)
if len(self._trend_values) <= tsb:
return
index = len(self._trend_values) - (tsb + 1)
if index < 0:
return
selected = self._trend_values[index]
up_val = selected[0]
down_val = selected[1]
if up_val > down_val:
self._trend_direction = 1
elif up_val < down_val:
self._trend_direction = -1
else:
self._trend_direction = 0
def _process_signal(self, candle):
if candle.State != CandleStates.Finished:
return
if self._signal_calculator is None:
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
value = self._signal_calculator.process(candle)
if value is None:
return
self._signal_values.append(value)
ssb = int(self._signal_signal_bar.Value)
max_count = max(ssb + 10, 48)
if len(self._signal_values) > max_count:
self._signal_values.pop(0)
if len(self._signal_values) <= ssb + 1:
return
current_index = len(self._signal_values) - (ssb + 1)
previous_index = current_index - 1
if current_index < 0 or previous_index < 0:
return
current = self._signal_values[current_index]
previous = self._signal_values[previous_index]
close_long = bool(self._close_long_on_signal_cross.Value) and previous[0] < previous[1]
close_short = bool(self._close_short_on_signal_cross.Value) and previous[0] > previous[1]
open_long = False
open_short = False
if self._trend_direction < 0:
if bool(self._close_long_on_trend_flip.Value):
close_long = True
if self._cooldown_remaining == 0 and bool(self._allow_short_entries.Value) and current[0] >= current[1] and previous[0] < previous[1]:
open_short = True
elif self._trend_direction > 0:
if bool(self._close_short_on_trend_flip.Value):
close_short = True
if self._cooldown_remaining == 0 and bool(self._allow_long_entries.Value) and current[0] <= current[1] and previous[0] > previous[1]:
open_long = True
submitted = False
if close_long and self.Position > 0:
self.SellMarket()
submitted = True
if close_short and self.Position < 0:
self.BuyMarket()
submitted = True
if open_long and self.Position <= 0 and bool(self._allow_long_entries.Value):
self.BuyMarket()
submitted = True
elif open_short and self.Position >= 0 and bool(self._allow_short_entries.Value):
self.SellMarket()
submitted = True
if submitted:
self._cooldown_remaining = int(self._signal_cooldown_bars.Value)
def OnReseted(self):
super(ibs_rsi_cci_v4_x2_strategy, self).OnReseted()
self._trend_values = []
self._signal_values = []
self._trend_direction = 0
self._cooldown_remaining = 0
if self._trend_calculator is not None:
self._trend_calculator.reset()
if self._signal_calculator is not None:
self._signal_calculator.reset()
self._trend_calculator = None
self._signal_calculator = None
def CreateClone(self):
return ibs_rsi_cci_v4_x2_strategy()