GitHub で見る
Up3x1 クロハボール シフト戦略
概要
up3x1 Krohabor D 戦略は、MetaTrader 4 エキスパート アドバイザー up3x1_Krohabor_D.mq4 の変換です。 3 つの変位単純移動平均 (SMA) を並べて、アクティブなタイムフレームでのトレンド継続ブレイクアウトを検出するという元のアイデアを維持しています。 C# 実装では、リスクとポジションの管理を .NET 環境に適応させながら、ローソク足サブスクリプションとインジケーター バインディングを備えた高レベルの StockSharp API を使用します。
取引ロジック
- 3 つの SMA は商品の終値に基づいて計算されます。
- 速い SMA (デフォルトは 24 小節)
- 中 SMA (デフォルトは 60 バー)
- 遅い SMA (デフォルトは 120 小節)
- すべての移動平均は、設定可能な完了ローソク足の数 (デフォルトは 6) だけ前方にシフトされます。この戦略は、各平均について、現在のシフト値と前のローソク足の値を比較します。
- ロングエントリーの要件:
- 現在および以前のスロー SMA の値は両方とも、現在および以前のファースト/ミディアム SMA の値を下回っており、強気の分離を示しています。
- 中間値 SMA は、高速値 SMA に比べて下落しています (以前の中間値は前の高速値を上回り、現在の中間値は現在の高速値を下回っています)。
- 短いエントリは、すべての比較が逆になった長いロジックを反映します。
- 一度にオープンできるポジションは 1 つだけです。アクティブなポジションがない場合、ストラテジーは新しいエントリーシグナルを待ちます。それ以外の場合は出口を管理します。
終了ルールと保護
- 初期の保護命令は、ローソク足の高値と安値を監視することでシミュレートされます。
- ストップロス距離は価格ステップ (デフォルトは 110 ポイント) で表され、ポジションがオープンされると適用されます。
- 利食い距離は同じ表現を使用します (デフォルトは 5 ポイント)。
- 未実現利益が設定されたしきい値を超えると、トレーリング ストップ (デフォルトは 10 ポイント) が有効になります。ストップはオープンポジションを支持して市場に従いますが、後退することはありません。
- 移動平均反転エグジットは、元の EA の終了ロジックを模倣し、速い SMA が中程度の平均と遅い平均を通過したときに取引を終了します。
- 連続損失後の動的な出来高減少は、MT4 スクリプトの動作を再現します。取引サイズは、最小出来高の下限を尊重しながら、負けた取引の数に比例して減少します。
パラメーター
| 名前 |
説明 |
FastPeriod |
高速の SMA の期間。 |
MediumPeriod |
媒体 SMA の期間。 |
SlowPeriod |
遅い SMA の期間。 |
MaShift |
すべての移動平均を前方にシフトするために使用される完了したローソク足の数。 |
Volume |
新規エントリーの基本注文量。 |
MinVolume |
損失ベースの調整後の最小許容ボリューム。 |
LossReductionFactor |
連続負けトレード後に取引高を縮小するときに適用される除数。 |
StopLossPoints |
価格ステップで測定されるストップロス距離。 |
TakeProfitPoints |
価格ステップで測定される利食い距離。 |
TrailingPoints |
価格ステップにおけるトレーリングストップ距離とアクティベーションしきい値。 |
CandleType |
分析に使用されるローソク足のデータ タイプ (タイムフレーム)。 |
注意事項
- この戦略では、
SubscribeCandles と Bind を併用してインジケーター出力をストリーミングし、手動によるインジケーター値の取得を回避します。
- ストップロス、テイクプロフィット、およびトレーリング動作は、ブローカーから独立した状態を保つために戦略ループ内に実装されています。ライブ取引環境では、必要に応じてこれらのブロックを実際の保護注文に置き換えることができます。
- ソース コード内のすべてのコメントは、プロジェクト ガイドラインに準拠するために英語で書かれています。
- 自動テストは提供されません。 StockSharp 内でバックテストを使用して、機器のパラメータ セットを検証します。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Up3x1KrohaborShiftStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose; private decimal _prevMid; private bool _hasPrev;
private int _cooldown;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Up3x1KrohaborShiftStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 20).SetDisplay("Channel Period", "Channel lookback", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA filter", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevMid = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
var close = candle.ClosePrice;
var mid = (highest + lowest) / 2;
if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevClose = close; _prevMid = mid;
return;
}
if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 6;
}
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 6;
}
_prevClose = close; _prevMid = mid;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class up3x1_krohabor_shift_strategy(Strategy):
def __init__(self):
super(up3x1_krohabor_shift_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 20).SetDisplay("Channel Period", "Channel lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown = 0
@property
def channel_period(self): return self._channel_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(up3x1_krohabor_shift_strategy, self).OnReseted()
self._prev_close = 0.0; self._prev_mid = 0.0; self._has_prev = False; self._cooldown = 0
def OnStarted2(self, time):
super(up3x1_krohabor_shift_strategy, self).OnStarted2(time)
self._has_prev = False; self._cooldown = 0
highest = Highest(); highest.Length = self.channel_period
lowest = Lowest(); lowest.Length = self.channel_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self.process_candle).Start()
def process_candle(self, candle, highest, lowest):
if candle.State != CandleStates.Finished: return
if not self.IsFormedAndOnlineAndAllowTrading(): return
close = float(candle.ClosePrice)
mid = (float(highest) + float(lowest)) / 2.0
if not self._has_prev:
self._prev_close = close; self._prev_mid = mid; self._has_prev = True; return
if self._cooldown > 0:
self._cooldown -= 1; self._prev_close = close; self._prev_mid = mid; return
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume); self._cooldown = 6
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume); self._cooldown = 6
self._prev_close = close; self._prev_mid = mid
def CreateClone(self): return up3x1_krohabor_shift_strategy()