GitHub で見る

Renkoレベル戦略

概要

Renkoレベル戦略はMetaTrader 5エキスパートアドバイザー「Renko Level EA」の忠実な変換です。StockSharp内でインジケーター駆動型のロジックを再構築し、丸められたRenkoレベルが新しいブロックにジャンプするたびに取引します。戦略は各レベルのシフトを合成Renkoレンガのブレイクアウトとして解釈し、ブレイクアウトの方向、または逆モードが有効な場合は反対方向にエントリーします。

システムは通常の時間ベースのロウソク足(デフォルトでは1分)をデータフィードとしてのみ使用します。ロウソク足のクローズはRenkoデータサブスクリプションを必要とせずにRenkoレンガをエミュレートする設定可能なブロックサイズに丸められます。丸められたブロックが変わるたびに、戦略は反対方向のエクスポージャーを決済し、検出された動きに合わせた新しいポジションを開きます。

取引ロジック

  1. 初期化
    • 銘柄からpipサイズを検出します(PriceStep)。
    • Block Sizeパラメーターをpipから価格単位に変換します(3桁および5桁の銘柄はpip値を自動的に10倍にします)。
    • 最初の完了したロウソク足のクローズを最も近いブロックに丸めて初期の上部と下部のRenkoレベルを作成します。
  2. レベルの維持
    • 各完了したロウソク足でクローズ価格が最も近いブロックサイズに丸められます。
    • クローズが現在のブロック内に留まる場合、保存されたレベルは変更されません。
    • クローズが下限を下回ると、アルゴリズムは価格を切り捨ててブロックを下にシフトします(lower = roundupper = round + size)。
    • クローズが上限を上回ると、ブロックは上にシフトされます(upper = roundlower = round - size)。
  3. シグナル生成
    • 上昇する上部レベルはRenkoブロックの強気のブレイクアウトを示します。下降する上部レベルは弱気のブレイクアウトを示します。
    • Reverseが無効な場合、戦略は強気シフトで買い、弱気シフトで売ります。Reverseが有効な場合、アクションが入れ替わります。
    • シグナルがトリガーされると、反対方向の既存のエクスポージャーが自動的に清算されます(買い注文はショートを決済、売り注文はロングを決済)。Allow Increaseが無効な場合、戦略は同じ方向のすでに開いているポジションの上にサイズを追加することを拒否します。
  4. 注文実行
    • 注文は戦略のVolume設定で送信されます。既存のポジションを反転する場合、注文サイズは絶対ポジションに設定されたボリュームを加えた値に等しく、フリップが即座に発生します。
    • StartProtection()は起動時に呼び出され、Designerまたはコンポジションを通じて設定されたリスク保護がアクティブになります。

パラメーター

パラメーター 説明 デフォルト
Block Size pipでのRenkoブロックサイズ。戦略はこれを銘柄のpip値で乗算して実際の価格増分を得ます。値が大きいほど取引頻度が減ります。 30
Reverse trueの場合、すべての取引シグナルを反転します(弱気シフトで買い、強気シフトで売り)。 false
Allow Increase trueの場合、各シグナルで同じ方向に追加注文を追加することでピラミッドを許可します。falseの場合、反対側を決済した後にネットポジションがフラットな場合にのみ新しい注文が送信されます。 false
Candle Type ソースロウソク足データ。サポートされている任意のDataTypeを使用できます;デフォルトでは戦略は1分ロウソク足をサブスクライブします。 TimeFrame(1m)
Volume (継承) マーケット注文を送信する際に使用する注文サイズ。開始前にストラテジーインスタンスでこのプロパティを設定してください。 ポートフォリオによる

使用上の注意

  • 銘柄のボラティリティに応じてブロックサイズを選択します。主要な外為ペアでは30〜50 pipが元のEAの動作をエミュレートします。指数または暗号資産ではより大きなブロックサイズを使用します。
  • 戦略はロウソク足のクローズが望ましい価格サンプリングを反映している限り、任意のロウソク足フィード(ティック、時間軸、レンジ)で動作します。純粋なRenkoフィードには、ロウソク足タイプをRenkoデータシリーズに切り替えることができます。
  • Reverseを有効にして、各Renkoレベル変化をフェードするブレイクアウトシステムを平均回帰システムに変換します。
  • Allow Increaseをオンにして、同じ方向の各新しいレベルでコントラクトを追加する元のEAの「Increase」パラメーターを模倣できます。
  • リスクとマネーマネジメント(ストップロス、テイクプロフィット、ドローダウン制御)はStockSharpの保護またはラッパー戦略を通じて設定できます。サンプルはMT5エキスパートと同一のロジックを維持し、レベルフリップを超えた固定出口を課しません。

データ要件

  • 設定されたCandle Typeの過去および リアルタイムのロウソク足データ。
  • pip変換が正しく機能するために、銘柄のメタデータがPriceStepDecimalsを提供する必要があります。これらの値が利用できない場合、戦略はデフォルトのステップ0.0001にフォールバックします。

推奨ワークフロー

  1. Designer に戦略を追加するか、StockSharp APIを通じてプログラムで作成します。
  2. SecurityPortfolioVolumeを設定し、オプションで上記のパラメーターを調整します。
  3. 戦略を開始します。最初の完了したロウソク足を待って初期のRenkoブロックを確立します。
  4. 内蔵のトレードチャートを監視するかログをサブスクライブして、丸められたレベルが変化したときにのみ注文がトリガーされることを確認します。

このドキュメントは元のRenko Level EAの動作を反映しながら、さらにカスタマイズまたは拡張できるようにStockSharp内での実装方法を説明しています。

using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Renko level breakout strategy. Emulates Renko bricks on time-based candles
/// and trades when the rounded level shifts up or down.
/// </summary>
public class RenkoLevelStrategy : Strategy
{
	private readonly StrategyParam<int> _blockSize;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _upperLevel;
	private decimal _lowerLevel;
	private bool _hasLevels;

	public int BlockSize
	{
		get => _blockSize.Value;
		set => _blockSize.Value = value;
	}

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

	public RenkoLevelStrategy()
	{
		_blockSize = Param(nameof(BlockSize), 5000)
			.SetGreaterThanZero()
			.SetDisplay("Block Size", "Renko block size in price steps", "Renko");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_upperLevel = 0m;
		_lowerLevel = 0m;
		_hasLevels = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

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

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

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

		var brickSize = GetBrickSize();
		if (brickSize <= 0m)
			return;

		var close = candle.ClosePrice;

		if (!_hasLevels)
		{
			InitializeLevels(close, brickSize);
			return;
		}

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var previousUpper = _upperLevel;
		var moved = false;

		if (close < _lowerLevel)
		{
			var (round, _, ceil) = CalculateLevels(close, brickSize);
			if (Math.Abs(round - _lowerLevel) > brickSize * 0.01m)
			{
				_lowerLevel = round;
				_upperLevel = ceil;
				moved = true;
			}
		}
		else if (close > _upperLevel)
		{
			var (round, floor, _) = CalculateLevels(close, brickSize);
			if (Math.Abs(round - _upperLevel) > brickSize * 0.01m)
			{
				_lowerLevel = floor;
				_upperLevel = round;
				moved = true;
			}
		}

		if (!moved)
			return;

		if (_upperLevel > previousUpper && Position <= 0)
			BuyMarket();
		else if (_upperLevel < previousUpper && Position >= 0)
			SellMarket();
	}

	private void InitializeLevels(decimal price, decimal brickSize)
	{
		var (round, floor, _) = CalculateLevels(price, brickSize);
		_upperLevel = round;
		_lowerLevel = floor;
		_hasLevels = true;
	}

	private (decimal round, decimal floor, decimal ceil) CalculateLevels(decimal price, decimal brickSize)
	{
		var ratio = price / brickSize;
		var rounded = Math.Round(ratio, 0, MidpointRounding.AwayFromZero);
		var priceRound = rounded * brickSize;
		var priceFloor = priceRound - brickSize;
		var priceCeil = priceRound + brickSize;
		return (priceRound, priceFloor, priceCeil);
	}

	private decimal GetBrickSize()
	{
		var step = Security?.PriceStep ?? 0.01m;
		return step * BlockSize;
	}
}