GitHub で見る

仮想通貨戦略

概要

Cryptos Strategy は、元の MetaTrader4 エキスパート アドバイザー cryptos.mq4 の高レベルの StockSharp 移植です。 ETH/USD ペアに焦点を当て、Bollinger バンドと線形加重移動平均 (LWMA) を組み合わせてボラティリティ圧縮からのブレイクアウトを捉えます。この戦略は、設定可能なローソク足の高値と安値のスイングを追跡し、検出された範囲の倍数としてテイクプロフィットターゲットを動的に計算します。

取引ロジック

  1. トレンド検出 – 終値が上部 Bollinger バンドに触れると戦略はショート バイアスに切り替わり、下部バンドに触れるとロング バイアスに切り替わります。また、バンドタッチでは、高値/安値の自動更新が無効になり、現在のスイング値が凍結されます。
  2. エントリー条件
    • 終値が LWMA を下回り、バイアスがショートし、アクティブなショート ポジションがない場合にショート ポジションをオープンします。
    • 終値が LWMA を上回り、バイアスが長く、アクティブなロングポジションがない場合にロングポジションをオープンします。
  3. 距離予測 – スイングの高値と安値 (自動または手動で固定) が LWMA からの距離を定義します。ティックで表されるこの距離にテイクプロフィット比率を掛けて、利益目標とリスクベースのポジションサイズを計算します。
  4. リスク管理 – この戦略は取引ごとのテイクプロフィットとストップロスのレベルを設定します。ロングの場合、ストップはスイングの下に低く配置されます。ショートの場合、スイングハイより上。ストップとターゲットはエントリごとに再計算され、戦略ループ内で適用されます。
  5. トレーリング イグジット – ロング ポジションが下側の Bollinger バンド (または上側バンドの上のショート) を下回ってクローズした場合、オープン ポジションはすぐにフラットになり、元の EA のトレーリング動作を模倣します。

パラメーター

パラメータ 説明
CandleType すべてのインジケーターの計算に使用されるローソク足シリーズのデータ型。
BollingerPeriod, BollingerWidth Bollinger バンドの長さと標準偏差の乗数。
MaPeriod 中央価格に基づく線形加重移動平均の期間。
LookbackCandles 自動スイングの高値/安値を決定するために検査されるローソク足の数。
TakeProfitRatio ETH/USDを取引する際の利益目標に使用される範囲乗数。
AlternativeTakeProfitRatio 他のすべてのシンボルに適用される範囲乗数。
RiskPerTrade 出来高計算ツールが各取引でリスクを負おうとする資本の量 (相場通貨)。
ValueIndex, CryptoValueIndex 非暗号通貨シンボルと暗号通貨シンボルそれぞれのリスクをボリュームに変換する乗数。
MinVolume, MaxVolume ボリュームステップを交換するための位置合わせ後のポジションサイズのハードバウンド。
MinRangeTicks ゼロ距離停止を回避するための最小許容投影範囲 (ティック単位)。
SpreadPoints ティック単位のスプレッドを手動でオーバーライドします (可能な場合は最高の買い値/売り値から自動検出されます)。
GlobalTrend 手動バイアス オーバーライド: 1 は短いセットアップを強制し、2 は長いセットアップを強制し、0 は戦略によって決定されます。
AutoHighLow 有効にすると、スイング ポイントがすべてのローソク足で再計算されます。無効にすると、次のバンドがタッチされるまでフリーズされます。
ManualBuyTrigger, ManualSellTrigger 即時のロングまたはショート エントリを要求するには、true に設定します (実行後にリセット)。
SkipBuys, SkipSells 新しいロングポジションまたはショートポジションのオープンを無効にします。

ポジションサイズ

この戦略は MT4 ロジック volume = RiskPerTrade / rangeTicks * valueIndex を複製します。結果は VolumeStep に揃えられ、MinVolume/MaxVolume と商品取引所が課す制限値の間でクリップされます。

使用上の注意

  • この戦略は開始時にポートフォリオの価値をチェックします。残高が RiskPerTrade * 3 未満の場合、取引は無効になり、EA の安全性チェックと一致する警告が記録されます。
  • 手動トリガーとバイアス制御により、ライブ取引中の裁量的決定と同期することが可能になります。
  • ETH/USD は自動的に CryptoValueIndexTakeProfitRatio を使用します。他の機器は代替パラメータに戻ります。
  • ストップとターゲットは戦略ループ内で強制されるため、追加の保護モジュールは必要ありません。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "Cryptos" MetaTrader expert.
/// Uses Bollinger Bands with a WMA trend filter. Buys when price is below WMA
/// and touches lower band; sells when price is above WMA and touches upper band.
/// </summary>
public class CryptosStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _wmaPeriod;
	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerWidth;

	private ExponentialMovingAverage _bandEma;
	private ExponentialMovingAverage _trendEma;

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

	public int WmaPeriod
	{
		get => _wmaPeriod.Value;
		set => _wmaPeriod.Value = value;
	}

	public int BollingerPeriod
	{
		get => _bollingerPeriod.Value;
		set => _bollingerPeriod.Value = value;
	}

	public decimal BollingerWidth
	{
		get => _bollingerWidth.Value;
		set => _bollingerWidth.Value = value;
	}

	public CryptosStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for signals", "General");

		_wmaPeriod = Param(nameof(WmaPeriod), 55)
			.SetGreaterThanZero()
			.SetDisplay("WMA Period", "Weighted moving average period", "Indicators");

		_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");

		_bollingerWidth = Param(nameof(BollingerWidth), 2m)
			.SetGreaterThanZero()
			.SetDisplay("BB Width", "Bollinger Bands deviation", "Indicators");
	}

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

		_bandEma = new ExponentialMovingAverage { Length = BollingerPeriod };
		_trendEma = new ExponentialMovingAverage { Length = WmaPeriod };

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

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

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

		if (!_bandEma.IsFormed || !_trendEma.IsFormed)
			return;

		var close = candle.ClosePrice;
		var bandOffset = bandValue * (BollingerWidth / 100m);
		var upperBand = bandValue + bandOffset;
		var lowerBand = bandValue - bandOffset;

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		// Buy: price below WMA, touches lower band
		if (close < trendValue && close <= lowerBand)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		// Sell: price above WMA, touches upper band
		else if (close > trendValue && close >= upperBand)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		// Exit at WMA cross
		if (Position > 0 && close >= upperBand)
			SellMarket(Position);
		else if (Position < 0 && close <= lowerBand)
			BuyMarket(Math.Abs(Position));
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_bandEma = null;
		_trendEma = null;

		base.OnReseted();
	}
}