GitHub で見る

FRASMAv2 戦略

Fractal Adaptive Simple Moving Average(FRASMAv2)に基づく戦略。

この戦略はFractal Dimensionインジケーターを使用してFractal Adaptive Simple Moving Averageを計算します。インジケーターの色は傾きに応じて変化します:上昇時は緑、横ばい時はグレー、下降時はマゼンタ。戦略は最後の確定足における色の変化を監視します:

  • 前のバーでインジケーターが緑で、最後のバーで緑以外(グレーまたはマゼンタ)になった場合、戦略はショートポジションを決済し、新しいロングポジションを開きます。
  • インジケーターがマゼンタで、マゼンタ以外になった場合、戦略はロングポジションを決済し、新しいショートポジションを開きます。

リスク管理はポイントで指定したストップロスとテイクプロフィットのパラメーターを使用します。

詳細

  • エントリー条件:FRASMAv2の色変化。
  • ロング/ショート:両方向。
  • エグジット条件:反対の色変化。
  • ストップ:保護モジュールによるテイクプロフィットとストップロス。
  • デフォルト値
    • Period = 30
    • TakeProfit = 2000ポイント
    • StopLoss = 1000ポイント
    • CandleType = TimeSpan.FromHours(4)
  • フィルター
    • カテゴリ:トレンド転換
    • 方向:両方
    • インジケーター:FractalDimension, FRASMAv2
    • ストップ:はい
    • 複雑さ:中級
    • 時間軸:4h
    • 季節性:いいえ
    • ニューラルネットワーク:いいえ
    • ダイバージェンス:いいえ
    • リスクレベル:中
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>
/// Strategy based on Fractal Adaptive Simple Moving Average (FRASMAv2).
/// Computes FRAMA from fractal dimension, trades on color (slope direction) changes.
/// </summary>
public class FrasmaV2Strategy : Strategy
{
	private readonly StrategyParam<int> _period;
	private readonly StrategyParam<DataType> _candleType;

	private bool _isFirst;
	private decimal _prevFrama;
	private int _prevColor;

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

	public FrasmaV2Strategy()
	{
		_period = Param(nameof(Period), 30)
			.SetGreaterThanZero()
			.SetDisplay("Period", "FRAMA calculation period", "Indicator");

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

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_isFirst = true;
		_prevFrama = 0;
		_prevColor = 1;
	}

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

		_isFirst = true;
		_prevFrama = 0;
		_prevColor = 1;

		var fdi = new FractalDimension { Length = Period };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(fdi, ProcessCandle)
			.Start();

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

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

		if (!fdiValue.IsFinal)
			return;

		var fdi = fdiValue.GetValue<decimal>();
		var alpha = (decimal)Math.Exp(-4.6 * ((double)fdi - 1.0));
		alpha = Math.Max(0.01m, Math.Min(1m, alpha));

		var price = candle.ClosePrice;
		var frama = _isFirst ? price : alpha * price + (1 - alpha) * _prevFrama;

		int color;
		if (_isFirst)
		{
			color = 1;
			_isFirst = false;
		}
		else if (frama > _prevFrama)
			color = 0; // Uptrend
		else if (frama < _prevFrama)
			color = 2; // Downtrend
		else
			color = 1; // Flat

		// Uptrend ended (color was 0, now > 0) -> sell signal
		if (_prevColor == 0 && color > 0 && Position >= 0)
			SellMarket();
		// Downtrend ended (color was 2, now < 2) -> buy signal
		else if (_prevColor == 2 && color < 2 && Position <= 0)
			BuyMarket();

		_prevFrama = frama;
		_prevColor = color;
	}
}