Diese Strategie handelt auf Basis eines geglätteten Force Index, der benutzerdefinierte Niveaus kreuzt. Wenn der Indikator über das hohe Niveau steigt oder unter das niedrige Niveau fällt, öffnet oder schließt die Strategie Positionen je nach gewähltem Handelsmodus. Der Force Index wird aus der Preisänderung und dem Volumen berechnet und mit einer EMA geglättet.
Details
Einstiegskriterien
Direkter Modus:
Long: Indikator kreuzt HighLevel nach oben.
Short: Indikator kreuzt LowLevel nach unten.
Gegen-Modus:
Long: Indikator kreuzt LowLevel nach unten.
Short: Indikator kreuzt HighLevel nach oben.
Ausstiegskriterien
Direkter Modus:
Long: Kreuzung unter LowLevel.
Short: Kreuzung über HighLevel.
Gegen-Modus:
Long: Kreuzung über HighLevel.
Short: Kreuzung unter LowLevel.
Stops: Nein.
Standardwerte:
Period = 30
HighLevel = 0
LowLevel = 0
Candle Type = 4-hour
Filter:
Kategorie: Momentum
Richtung: Beide
Indikatoren: Force Index
Stops: Nein
Komplexität: Mittel
Zeitrahmen: Mittelfristig
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Fractal Force Index strategy.
/// Uses EMA of price changes as a momentum measure.
/// Opens or closes positions based on indicator level crossovers.
/// </summary>
public class FractalForceIndexStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevEma;
private decimal _prevClose;
private bool _hasPrev;
/// <summary>
/// EMA smoothing period.
/// </summary>
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
/// <summary>
/// The type of candles used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="FractalForceIndexStrategy"/>.
/// </summary>
public FractalForceIndexStrategy()
{
_period = Param(nameof(Period), 21)
.SetGreaterThanZero()
.SetDisplay("Period", "EMA length", "Indicator")
.SetOptimize(5, 30, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for indicator", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevEma = 0m;
_prevClose = 0m;
_hasPrev = false;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (_hasPrev)
{
// Force-like momentum: price relative to EMA direction
var crossedAbove = _prevClose <= _prevEma && close > emaValue;
var crossedBelow = _prevClose >= _prevEma && close < emaValue;
if (crossedAbove && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (crossedBelow && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
}
_prevClose = close;
_prevEma = emaValue;
_hasPrev = true;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class fractal_force_index_strategy(Strategy):
"""
Fractal Force Index: EMA crossover momentum strategy.
Opens positions when close crosses above/below EMA.
"""
def __init__(self):
super(fractal_force_index_strategy, self).__init__()
self._period = self.Param("Period", 21) \
.SetDisplay("Period", "EMA length", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Timeframe for indicator", "General")
self._prev_ema = 0.0
self._prev_close = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(fractal_force_index_strategy, self).OnReseted()
self._prev_ema = 0.0
self._prev_close = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(fractal_force_index_strategy, self).OnStarted2(time)
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self._period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema = float(ema_value)
if self._has_prev:
crossed_above = self._prev_close <= self._prev_ema and close > ema
crossed_below = self._prev_close >= self._prev_ema and close < ema
if crossed_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif crossed_below and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_ema = ema
self._has_prev = True
def CreateClone(self):
return fractal_force_index_strategy()