GitHub で見る

RangeEA ウィークリー グリッド戦略

概要

RangeEA Weekly Grid Strategy は、オリジナルの MetaTrader エキスパート アドバイザーから変換された指値注文グリッド システムです。アルゴリズムは現在の 毎週の取引範囲を設定し、設定可能な保留中の指値注文の数を入力します。各注文は動的なストップロスを使用し、 利食いオフセットは、指値価格と現在の市場価格の間の距離に応じて調整され、同時に以下の条件も考慮されます。 ポイントで表される最小距離。ポートフォリオの資本が 1 倍増加したら帳簿全体をクローズすることで利益を確定できます。 事前に定義された割合。

この実装では、StockSharp の高レベルの API を利用します。ローソク足が意思決定ロジックを駆動し、未決注文は 戦略ヘルパー メソッドとリスク コントロールは、最適化の準備ができたパラメーターとして公開されます。

取引ロジック

  1. 2 つのキャンドル ストリームを購読します。
    • グリッドのメンテナンスを促進するユーザー定義の時間枠 (デフォルトでは 1 時間)。
    • 現在の取引範囲を推定するために使用される週ごとのローソク足。
  2. 完了した週次ローソク足ごとに、過去 2 週間の最高値と最低値を更新します。彼らの違いは次のようになります アクティブな取引範囲。
  3. 終了した取引ローソクごとに次のようになります。
    • 設定された取引ウィンドウ (StartTradeHourEndTradeHour) を尊重してください。
    • 必要に応じて、各取引日の初めにグリッドをリセットします。
    • 未決の指値注文が存在しない場合は、新しい注文をレンジの下限と上限の間で均等に分配します。
    • 2 つの注文がすでに約定された後、グリッドが終了したときに最後から 2 番目の約定を同じ価格の新しい注文に置き換えます。 NumberOfOrders - 2 個のアイテムに縮小されます。
    • アカウントの資本を継続的に監視し、設定された利益率に達したらすべてを清算します。
  4. 取引ウィンドウが閉じ、CloseAllAtEndTrade が有効になったら、すべての未決注文をキャンセルし、既存のポジションを終了します。

パラメーター

名前 説明 デフォルト
CandleType グリッドメンテナンスをトリガーするために使用される取引時間枠。 1時間キャンドル
WeeklyCandleType 範囲境界を導出するために使用される時間枠。 1週間キャンドル
StartTradeHour 新しい注文ができる時間帯。 0
EndTradeHour 取引が停止する時刻。 24
CloseAllAtEndTrade 取引ウィンドウの外ですべての注文とポジションを閉じます。 本当の
MaxOpenOrders 同時注文とポジションの最大数。 5
NumberOfOrders グリッド内の指値注文の数。 10
OrderVolume 各注文に使用される量。 0.01
ResetOrdersDaily 各取引日の開始時にグリッドを再構築します。 本当の
StopLossPoints ポイント単位の最小ストップロス距離。 60
TakeProfitPoints ポイント単位の最小利食い距離。 60
StopLossMultiplier 動的ストップロス距離に適用される乗数。 3
TakeProfitMultiplier 動的なテイクプロフィットディスタンスに適用される乗数。 1
TargetPercentage 清算を引き起こす株式利益の割合。 8

リスク管理

  • この戦略は、アクティブな注文とポジションの数を制御するために、MaxOpenOrders の制限を尊重します。
  • ストップロスとテイクプロフィットのレベルは、常にエントリーから設定されたポイント数以上離れており、オプションで設定できます。 乗算器パラメータによって拡張されます。
  • 毎日のリセット オプションにより、古い注文が新しいセッションに持ち込まれるのを防ぎます。
  • ポートフォリオレベルの株式目標により、帳簿を平坦化することで利益を固定する戦略が可能になります。

注意事項

  • 選択した証券が毎週のローソク足を提供していることを確認します。そうしないと、ストラテジーは範囲を計算できません。
  • 標準以外の価格ステップを持つ商品を使用する場合は、基礎となるティックサイズと一致するようにポイントベースの設定を調整します。
  • NumberOfOrdersOrderVolume、およびストップ/テイク乗数を最適化すると、グリッドをさまざまなレベルに適応させるのに役立ちます ボラティリティ。
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Range based grid strategy that detects the trading range from recent price action
/// and places buy/sell limit orders at grid levels within the range.
/// Buys at lower grid levels, sells at upper grid levels.
/// </summary>
public class RangeWeeklyGridStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rangePeriod;
	private readonly StrategyParam<int> _gridLevels;

	private decimal _rangeHigh;
	private decimal _rangeLow;
	private bool _rangeSet;
	private decimal _entryPrice;
	private DateTimeOffset _lastTradeTime;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int RangePeriod
	{
		get => _rangePeriod.Value;
		set => _rangePeriod.Value = value;
	}

	public int GridLevels
	{
		get => _gridLevels.Value;
		set => _gridLevels.Value = value;
	}

	public RangeWeeklyGridStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Primary candle type", "General");

		_rangePeriod = Param(nameof(RangePeriod), 100)
			.SetDisplay("Range Period", "Number of candles to determine range", "Logic");

		_gridLevels = Param(nameof(GridLevels), 5)
			.SetDisplay("Grid Levels", "Number of grid levels within the range", "Logic");
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_rangeHigh = 0;
		_rangeLow = 0;
		_rangeSet = false;
		_entryPrice = 0;
		_lastTradeTime = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var highest = new Highest { Length = RangePeriod };
		var lowest = new Lowest { Length = RangePeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(highest, lowest, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal highestValue, decimal lowestValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (highestValue <= 0 || lowestValue <= 0 || highestValue <= lowestValue)
			return;

		_rangeHigh = highestValue;
		_rangeLow = lowestValue;
		_rangeSet = true;

		if (!_rangeSet)
			return;

		var range = _rangeHigh - _rangeLow;
		if (range <= 0)
			return;

		// Cooldown: at least 1 day between trades
		if (_lastTradeTime != default && candle.CloseTime - _lastTradeTime < TimeSpan.FromDays(1))
			return;

		var gridStep = range / (GridLevels + 1);
		var close = candle.ClosePrice;
		var mid = (_rangeHigh + _rangeLow) / 2;

		// Buy when price is in lower portion of range
		if (close <= _rangeLow + gridStep && Position <= 0)
		{
			BuyMarket();
			_entryPrice = close;
			_lastTradeTime = candle.CloseTime;
		}
		// Sell when price is in upper portion of range
		else if (close >= _rangeHigh - gridStep && Position >= 0)
		{
			SellMarket();
			_entryPrice = close;
			_lastTradeTime = candle.CloseTime;
		}
		// Take profit at mid-range
		else if (Position > 0 && close >= mid)
		{
			SellMarket();
			_lastTradeTime = candle.CloseTime;
		}
		else if (Position < 0 && close <= mid)
		{
			BuyMarket();
			_lastTradeTime = candle.CloseTime;
		}
	}
}