GitHub で見る
Flat 001a レンジ戦略
概要
Flat 001a は、EURUSD の時間足チャート用に設計されたスキャルピング システムです。最新の 3 つの時間足ローソク足をスキャンし、最高値と最低値の間の距離を測定します。この 3 本のローソク足ウィンドウの範囲が設定可能なポイント数内に収まる場合、戦略は価格がフラット内に閉じ込められたままになると予測します。その後、海峡の上層または下層への短期的な上昇をフェードアウトすることを検討し、すぐに保護命令を出します。
元の MQL4 エキスパート アドバイザーは、上半期には EURUSD のみを取引し、シンボルまたは時間枠が間違っていた場合は取引を拒否しました。このポートは同じデフォルト (EURUSD、60 分足のローソク足) を維持し、すべてのエントリー、ストップロス、テイクプロフィット、トレーリングストップの計算を StockSharp で再現します。
指標とデータ
Highest および Lowest インジケーター (期間 = 3) は、終了した最後の 3 つのローソク足の上下を追跡します。
- ソース コードの H1 要件を反映するために、タイムフレーム パラメーターのデフォルトは 60 分足のローソク足です。
- 追加のオシレーターや平滑化フィルターは使用されないため、この戦略は生の価格の極端な値だけに反応します。
エントリーロジック
- サブスクリプションのキャンドルが閉じるまで待ちます。完成したキャンドルのみが加工されます。
- 現在のセキュリティ コードが設定されたコードと一致することを確認します (デフォルト:
EURUSD)。そうでない場合、戦略はアイドル状態のままになります。
- オプションの取引ウィンドウを評価します。デフォルトでは、エントリはプラットフォーム時間の深夜 0 時から始まる 2 時間 (0 時と 1 時) の間許可されます。フィルターは無効にすることができます。
- 3 本のローソク足の範囲
range = highest - lowest を計算し、それを商品 PriceStep を介してポイントに変換します。
- ポイント数が
DiffMinPoints と DiffMaxPoints の間にある場合にのみ続行します。
- 終値がレンジの下限 4 分の 1 以内にあり、オープンポジションがない場合は、ロング取引に入ります。
- 終値がレンジの最高値の 4 分の 1 以内にあり、オープンなポジションがない場合は、空売り取引を開始します。
注文管理
- 最初のストップロス
- ロングトレード:
lowest - range / 3。
- ショートトレード:
highest + range / 3。
- 利益確定
- ロングトレード: エントリー価格 +
TakeProfitPoints * PriceStep。
- ショートトレード: エントリー価格 −
TakeProfitPoints * PriceStep。
- トレーリングストップ
- 未実現利益が
TrailingStopPoints * PriceStep を超えると、ストップロスはローソク足ごとに追跡されます。
- ロング取引では、現在のストップよりも高い場合、ストップが
closePrice - TrailingDistance に移動します。
- ショートトレードでは、現在のストップよりも低い場合、ストップを
closePrice + TrailingDistance に移動します。
- すべての決済は成行注文で実行されます。この戦略は、ストップロスまたはテイクプロフィットのいずれかのレベルが次のローソク足に触れたときにフルポジションをクローズします。
パラメーター
| グループ |
名前 |
説明 |
デフォルト |
| 一般 |
CandleType |
計算に使用されるローソクの種類。元のシステムに合わせて 60 分の時間枠に設定する必要があります。 |
TimeFrame(60m) |
| 一般 |
SecurityCode |
予期されるセキュリティ コード。金融商品を取引するには空のままにしてください。 |
EURUSD |
| 範囲フィルター |
DiffMinPoints |
取引に必要なポイントの最低 3 キャンドル範囲。 |
18 |
| 範囲フィルター |
DiffMaxPoints |
取引できるポイントの最大 3 キャンドル範囲。 |
28 |
| 取引ウィンドウ |
EnableTimeFilter |
時間フィルターを有効または無効にします。 |
true |
| 取引ウィンドウ |
OpenHour |
取引ウィンドウの開始時間 (0 ~ 23)。この戦略では、次の 1 時間の即時対応も可能です。 |
0 |
| リスク管理 |
TakeProfitPoints |
ポイントで表されるテイクプロフィット距離。無効にするには、ゼロに設定します。 |
8 |
| リスク管理 |
TrailingStopPoints |
トレーリングストップの距離をポイントで表します。末尾を無効にするには、ゼロに設定します。 |
6 |
実践メモ
- StockSharp
Strategy.Volume プロパティは注文サイズを制御します。ブローカー契約の規模に応じて調整してください。
- 選択した機器が有効な
PriceStep を公開していることを確認してください。 PriceStep が欠落している場合、戦略は 1 にフォールバックし、警告をログに記録します。
- MQL4 の専門アドバイザーは、口座残高に応じてロットを調整するオプションの資金管理を提供しました。 StockSharp のサンプルはポジション サイズを一定に保ちます。必要に応じて、独自のボリューム管理のスクリプトを作成できます。
- ストラテジーを実際に実行する前に、必ずシミュレーションでテストしてください。トレーリングロジックは、ローソク足の極値がそのレベルを横切ったときにブローカーが保護注文を約定することを前提としています。速い市場では、スリッページにより実現リスクが増大する可能性があります。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Flat 001a: RSI reversal with EMA filter and ATR stops.
/// </summary>
public class Flat001aStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevRsi;
private decimal _entryPrice;
public Flat001aStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_emaLength = Param(nameof(EmaLength), 20)
.SetDisplay("EMA Length", "Trend filter.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = 0; _entryPrice = 0;
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ema, atr, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
if (_prevRsi == 0 || atrVal <= 0) { _prevRsi = rsiVal; return; }
var close = candle.ClosePrice;
if (Position > 0)
{
if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 70) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 30) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (rsiVal > 55 && _prevRsi <= 55 && close > emaVal) { _entryPrice = close; BuyMarket(); }
else if (rsiVal < 45 && _prevRsi >= 45 && close < emaVal) { _entryPrice = close; SellMarket(); }
}
_prevRsi = rsiVal;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage, AverageTrueRange
class flat001a_strategy(Strategy):
def __init__(self):
super(flat001a_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period.", "Indicators")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "Trend filter.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_rsi = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(flat001a_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
self._entry_price = 0.0
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiLength
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self._ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_val, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_val)
ev = float(ema_val)
av = float(atr_val)
if self._prev_rsi == 0 or av <= 0:
self._prev_rsi = rv
return
close = float(candle.ClosePrice)
if self.Position > 0:
if close >= self._entry_price + av * 2.5 or close <= self._entry_price - av * 1.5 or rv > 70:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close <= self._entry_price - av * 2.5 or close >= self._entry_price + av * 1.5 or rv < 30:
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_rsi = rv
return
if self.Position == 0:
if rv > 55 and self._prev_rsi <= 55 and close > ev:
self._entry_price = close
self.BuyMarket()
elif rv < 45 and self._prev_rsi >= 45 and close < ev:
self._entry_price = close
self.SellMarket()
self._prev_rsi = rv
def OnReseted(self):
super(flat001a_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._entry_price = 0.0
def CreateClone(self):
return flat001a_strategy()