GO-Strategie
Diese Strategie berechnet einen zusammengesetzten GO-Wert auf Basis exponentieller gleitender Durchschnitte (EMA) der Eröffnungs-, Hoch-, Tief- und Schlusskurse multipliziert mit dem Volumen. Handelsentscheidungen werden anhand des Vorzeichens und des Niveaus des GO-Wertes getroffen.
Formel
GO = ((C - O) + (H - O) + (L - O) + (C - L) + (C - H)) * V
Dabei gilt:
C,O,H,L– EMA-Werte der Schluss-, Eröffnungs-, Hoch- und Tief-Kurse.V– Volumen der verarbeiteten Kerze.
Handelsregeln
- Long eröffnen: GO >
OpenLevel - Short eröffnen: GO <
-OpenLevel - Long schließen: GO < (
OpenLevel-CloseLevelDiff) - Short schließen: GO > -(
OpenLevel-CloseLevelDiff)
Parameter
| Name | Beschreibung |
|---|---|
MaPeriod |
EMA-Periode für die Preisglättung. |
OpenLevel |
GO-Niveau zum Auslösen neuer Positionen. |
CloseLevelDiff |
Differenz zwischen Eröffnungs- und Schließniveau. |
ShowGo |
Ob GO-Werte protokolliert werden. |
CandleType |
Art der für die Verarbeitung verwendeten Kerzen. |
Die Strategie arbeitet auf abgeschlossenen Kerzen und verwendet Marktorders für das Positionsmanagement.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// GO strategy: EMA-smoothed OHLC composite multiplied by candle volume.
/// </summary>
public class GoStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _openLevel;
private readonly StrategyParam<decimal> _closeLevelDiff;
private readonly StrategyParam<bool> _showGo;
private readonly StrategyParam<DataType> _candleType;
private decimal? _openEma;
private decimal? _highEma;
private decimal? _lowEma;
private decimal? _closeEma;
private int _samples;
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
public decimal OpenLevel { get => _openLevel.Value; set => _openLevel.Value = value; }
public decimal CloseLevelDiff { get => _closeLevelDiff.Value; set => _closeLevelDiff.Value = value; }
public bool ShowGo { get => _showGo.Value; set => _showGo.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public GoStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("MA Period", "EMA period for O/H/L/C smoothing.", "GO");
_openLevel = Param(nameof(OpenLevel), 0m)
.SetNotNegative()
.SetDisplay("Open Level", "Absolute GO threshold required for entry.", "GO");
_closeLevelDiff = Param(nameof(CloseLevelDiff), 0m)
.SetNotNegative()
.SetDisplay("Close Level Diff", "Distance between entry and exit GO thresholds.", "GO");
_showGo = Param(nameof(ShowGo), false)
.SetDisplay("Show GO", "Log computed GO values.", "GO");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type.", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_openEma = null;
_highEma = null;
_lowEma = null;
_closeEma = null;
_samples = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType).Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_samples++;
_openEma = Ema(_openEma, candle.OpenPrice, MaPeriod);
_highEma = Ema(_highEma, candle.HighPrice, MaPeriod);
_lowEma = Ema(_lowEma, candle.LowPrice, MaPeriod);
_closeEma = Ema(_closeEma, candle.ClosePrice, MaPeriod);
if (_samples < MaPeriod)
return;
var go = CalculateGo(_openEma.Value, _highEma.Value, _lowEma.Value, _closeEma.Value, candle.TotalVolume);
if (ShowGo)
LogInfo("GO={0}", go);
var closeLevel = OpenLevel - CloseLevelDiff;
var position = Position;
if (position > 0m && go < closeLevel)
{
SellMarket(Math.Abs(position));
position = 0m;
}
else if (position < 0m && go > -closeLevel)
{
BuyMarket(Math.Abs(position));
position = 0m;
}
if (position != 0m)
return;
if (go > OpenLevel)
BuyMarket();
else if (go < -OpenLevel)
SellMarket();
}
internal static decimal CalculateGo(decimal openEma, decimal highEma, decimal lowEma, decimal closeEma, decimal volume)
=> ((closeEma - openEma) +
(highEma - openEma) +
(lowEma - openEma) +
(closeEma - lowEma) +
(closeEma - highEma)) * volume;
private static decimal Ema(decimal? previous, decimal value, int period)
{
if (previous is null)
return value;
var alpha = 2m / (period + 1m);
return previous.Value + alpha * (value - previous.Value);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class go_strategy(Strategy):
def __init__(self):
super(go_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 14).SetGreaterThanZero()
self._open_level = self.Param("OpenLevel", 0.0).SetNotNegative()
self._close_level_diff = self.Param("CloseLevelDiff", 0.0).SetNotNegative()
self._show_go = self.Param("ShowGo", False)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._open_ema = None
self._high_ema = None
self._low_ema = None
self._close_ema = None
self._samples = 0
def GetWorkingSecurities(self):
return [(self.Security, self._candle_type.Value)]
def OnReseted(self):
super(go_strategy, self).OnReseted()
self._open_ema = None
self._high_ema = None
self._low_ema = None
self._close_ema = None
self._samples = 0
def OnStarted2(self, time):
super(go_strategy, self).OnStarted2(time)
self.SubscribeCandles(self._candle_type.Value).Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
period = int(self._ma_period.Value)
self._samples += 1
self._open_ema = self._ema(self._open_ema, float(candle.OpenPrice), period)
self._high_ema = self._ema(self._high_ema, float(candle.HighPrice), period)
self._low_ema = self._ema(self._low_ema, float(candle.LowPrice), period)
self._close_ema = self._ema(self._close_ema, float(candle.ClosePrice), period)
if self._samples < period:
return
go = self.calculate_go(
self._open_ema, self._high_ema, self._low_ema, self._close_ema, float(candle.TotalVolume))
if bool(self._show_go.Value):
self.LogInfo("GO={0}", go)
open_level = float(self._open_level.Value)
close_level = open_level - float(self._close_level_diff.Value)
position = self.Position
if position > 0 and go < close_level:
self.SellMarket(Math.Abs(position))
position = 0
elif position < 0 and go > -close_level:
self.BuyMarket(Math.Abs(position))
position = 0
if position != 0:
return
if go > open_level:
self.BuyMarket()
elif go < -open_level:
self.SellMarket()
@staticmethod
def calculate_go(open_ema, high_ema, low_ema, close_ema, volume):
return ((close_ema - open_ema) +
(high_ema - open_ema) +
(low_ema - open_ema) +
(close_ema - low_ema) +
(close_ema - high_ema)) * volume
@staticmethod
def _ema(previous, value, period):
if previous is None:
return value
alpha = 2.0 / (period + 1.0)
return previous + alpha * (value - previous)
def CreateClone(self):
return go_strategy()