GitHub で見る

Crypto Scalper戦略

Crypto Scalper戦略は、StockSharpの高レベルコンポーネントで元のMetaTraderエキスパートロジックを再現します。主要時間軸で速い線形加重移動平均の強気または弱気のクロスオーバーを監視し、上位時間軸で計算されたトレンドフィルターでセットアップを確認します。条件が揃うと、戦略は成行注文を使用してエントリーし、MetaTraderのpipで測定されたストップロスとテイクプロフィット距離を通じて出口を管理します。

パラメーター

名前 説明 デフォルト値
Primary Candle 主要時間軸で処理するロウソク足タイプ。 1分時間軸
Higher Candle 確認に使用する上位時間軸のロウソク足タイプ。 15分時間軸
Fast LWMA 主要線形加重移動平均の長さ。 8
Higher Fast MA 確認時間軸での速いLWMAの長さ。 6
Higher Slow MA 確認時間軸での遅いLWMAの長さ。 85
Momentum Period 上位時間軸ロウソク足に適用するモメンタムインジケーターの長さ。 14
Momentum Threshold 取引に必要な参照モメンタム(MetaTraderベースライン100)からの最小偏差。 0.3
Momentum Reference MetaTraderのモメンタムスケーリングをエミュレートするために使用する参照レベル。 100
Stop Loss (pips) MetaTrader pipでの保護ストップ距離。 20
Take Profit (pips) MetaTrader pipでの保護利益距離。 50
Volume ロットで表現された注文ボリューム。 0.01
MACD Fast MACD確認用の速いEMA期間。 12
MACD Slow MACD確認用の遅いEMA期間。 26
MACD Signal MACD確認用のシグナルEMA期間。 9

トレードロジック

  1. 主要時間軸を購読し、価格に素早く反応するLWMAを計算します。
  2. 前のロウソク足がLWMAを上抜け(ロング)または下抜け(ショート)したときにエントリーを検出します。
  3. 上位時間軸フィルターを使用してクロスオーバーを確認します:
    • 上位の速いLWMAはロングエントリーでは上位の遅いLWMAの上、ショートエントリーでは下に留まる必要があります。
    • MACDヒストグラム(メイン引くシグナル)はロングでポジティブ、ショートでネガティブである必要があります。
    • モメンタムは参照レベルから少なくとも Momentum Threshold だけ偏差している必要があります。
  4. 他に注文がアクティブでなく、現在のポジションが許可する場合に、検出された方向で成行注文を送信します。
  5. 後続のロウソク足を監視し、ストップロスまたはテイクプロフィット価格に触れた場合にポジションを閉じます。

注意事項

  • 戦略はマニュアルインジケーターバッファを避けて Bind を使用したStockSharpの高レベルサブスクリプションを使用します。
  • 保護レベルは証券の価格ステップを使用して各ロウソク足で再計算されます。楽器が設定済みの価格ステップを公開していない場合は 0.0001 のフォールバックステップが適用されます。
  • 一度に許可されるポジションは1つだけです。既存の取引が完了するまで後続のシグナルは無視されます。
  • C#実装内のすべてのインラインコメントはリポジトリガイドラインに従って英語で書かれています。
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;

public class CryptoScalperStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public CryptoScalperStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}