Diese Strategie verwendet den Center of Gravity OSMA-Oszillator, um potenzielle Trendumkehrungen zu erkennen.
Der Oszillator multipliziert einfache und gewichtete gleitende Durchschnitte, glättet das Ergebnis zweimal und verfolgt
Richtungsänderungen. Wenn der Indikator ein lokales Minimum bildet und nach oben dreht, schließt die Strategie
Short-Positionen und kann eine neue Long-Position eröffnen. Wenn ein lokales Maximum nach unten dreht,
werden Long-Positionen geschlossen und optional Shorts eröffnet.
Funktionsweise
Der Schlusskurs wird als Eingabe für den benutzerdefinierten Indikator verwendet.
Der Indikator berechnet:
Einfachen gleitenden Durchschnitt (SMA) mit der Länge Period.
Gewichteten gleitenden Durchschnitt (WMA) mit derselben Länge.
Produkt dieser beiden Durchschnitte.
Zwei zusätzliche Glättungsschritte mit den Längen SmoothPeriod1 und SmoothPeriod2.
Handelsregeln:
Wenn der vorherige Wert kleiner als der Wert davor war und der aktuelle Wert größer als der vorherige ist, drehte der Oszillator nach oben. Jede Short-Position wird geschlossen und eine Long-Position kann eröffnet werden.
Wenn der vorherige Wert größer als der Wert davor war und der aktuelle Wert kleiner als der vorherige ist, drehte der Oszillator nach unten. Jede Long-Position wird geschlossen und eine Short-Position kann eröffnet werden.
Optionale Stop-Loss- und Take-Profit-Werte in Preiseinheiten schützen offene Positionen.
Parameter
Period – Basisperiode für SMA und WMA.
SmoothPeriod1 – Länge der ersten Glättungsstufe.
SmoothPeriod2 – Länge der zweiten Glättungsstufe.
StopLoss – Stop-Loss-Abstand in Preiseinheiten (0 zum Deaktivieren).
TakeProfit – Take-Profit-Abstand in Preiseinheiten (0 zum Deaktivieren).
BuyPosOpen – Eröffnung von Long-Positionen erlauben.
SellPosOpen – Eröffnung von Short-Positionen erlauben.
BuyPosClose – Long-Positionen bei einem Verkaufssignal schließen erlauben.
SellPosClose – Short-Positionen bei einem Kaufsignal schließen erlauben.
CandleType – Kerzentyp (Zeitrahmen) für Berechnungen.
Hinweise
Nur die C#-Version wird bereitgestellt. Der Python-Ordner ist absichtlich nicht vorhanden.
Verwenden Sie Tabulatoren für Einrückungen beim Ändern des Codes.
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>
/// Center of Gravity OSMA strategy.
/// Uses SMA vs WMA difference (center of gravity concept) direction changes for signals.
/// </summary>
public class CenterOfGravityOsmaStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevOsma;
private decimal _prevPrevOsma;
private int _count;
public int Period { get => _period.Value; set => _period.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public CenterOfGravityOsmaStrategy()
{
_period = Param(nameof(Period), 10)
.SetGreaterThanZero()
.SetDisplay("Period", "Calculation period", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevOsma = 0;
_prevPrevOsma = 0;
_count = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = Period };
var wma = new WeightedMovingAverage { Length = Period };
SubscribeCandles(CandleType)
.Bind(sma, wma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue, decimal wmaValue)
{
if (candle.State != CandleStates.Finished)
return;
var osma = smaValue - wmaValue;
_count++;
if (_count < 3)
{
_prevPrevOsma = _prevOsma;
_prevOsma = osma;
return;
}
// Buy when OSMA turns up
var turnUp = _prevOsma < _prevPrevOsma && osma > _prevOsma;
// Sell when OSMA turns down
var turnDown = _prevOsma > _prevPrevOsma && osma < _prevOsma;
if (turnUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (turnDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevPrevOsma = _prevOsma;
_prevOsma = osma;
}
}