Volume EA-Strategie
Überblick
Diese Strategie handelt auf Basis von Volumenspitzen und dem Commodity Channel Index (CCI). Sie eröffnet Positionen zu Beginn einer neuen Stunde, wenn das Volumen der vorherigen Kerze das der Kerze davor um einen konfigurierbaren Faktor übertrifft. CCI-Werte müssen in bestimmte Bänder fallen, um das Signal zu bestätigen.
Regeln
- Es ist immer nur eine Position gleichzeitig offen.
- Zu Beginn jeder Stunde:
- Long-Einstieg wenn:
- Die vorherige Kerze bullisch ist.
- Vorheriges Volumen > voriges Volumen ×
Factor. - CCI liegt zwischen
CciLevel1undCciLevel2.
- Short-Einstieg wenn:
- Die vorherige Kerze bärisch ist.
- Vorheriges Volumen > voriges Volumen ×
Factor. - CCI liegt zwischen
CciLevel4undCciLevel3.
- Long-Einstieg wenn:
- Ein Trailing-Stop von
TrailingStopPreisschritten schützt Gewinne. - Alle Positionen werden geschlossen, wenn die Stunde gleich 23 ist.
Parameter
Factor– Volumen-Multiplikator-Schwellenwert.TrailingStop– Trailing-Distanz in Preisschritten.CciLevel1/CciLevel2– CCI-Grenzen für Long-Trades.CciLevel3/CciLevel4– CCI-Grenzen für Short-Trades.CandleType– Kerzen-Zeitrahmen für Berechnungen.
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>
/// Strategy based on volume spikes and CCI ranges.
/// </summary>
public class VolumeEaStrategy : Strategy
{
private readonly StrategyParam<decimal> _factor;
private readonly StrategyParam<decimal> _trailingStop;
private readonly StrategyParam<decimal> _cciLevel1;
private readonly StrategyParam<decimal> _cciLevel2;
private readonly StrategyParam<decimal> _cciLevel3;
private readonly StrategyParam<decimal> _cciLevel4;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevVolume;
private decimal _prevPrevVolume;
private decimal _prevOpen;
private decimal _prevClose;
private decimal _longStop;
private decimal _shortStop;
/// <summary>
/// Volume multiplier threshold.
/// </summary>
public decimal Factor
{
get => _factor.Value;
set => _factor.Value = value;
}
/// <summary>
/// Trailing stop distance in price steps.
/// </summary>
public decimal TrailingStop
{
get => _trailingStop.Value;
set => _trailingStop.Value = value;
}
/// <summary>
/// Lower CCI level for long trades.
/// </summary>
public decimal CciLevel1
{
get => _cciLevel1.Value;
set => _cciLevel1.Value = value;
}
/// <summary>
/// Upper CCI level for long trades.
/// </summary>
public decimal CciLevel2
{
get => _cciLevel2.Value;
set => _cciLevel2.Value = value;
}
/// <summary>
/// Upper CCI level for short trades.
/// </summary>
public decimal CciLevel3
{
get => _cciLevel3.Value;
set => _cciLevel3.Value = value;
}
/// <summary>
/// Lower CCI level for short trades.
/// </summary>
public decimal CciLevel4
{
get => _cciLevel4.Value;
set => _cciLevel4.Value = value;
}
/// <summary>
/// Candle type for processing.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public VolumeEaStrategy()
{
_factor = Param(nameof(Factor), 1.55m)
.SetGreaterThanZero()
.SetDisplay("Factor", "Volume multiplier", "Trading");
_trailingStop = Param(nameof(TrailingStop), 350m)
.SetGreaterThanZero()
.SetDisplay("Trailing Stop", "Trailing distance in steps", "Risk");
_cciLevel1 = Param(nameof(CciLevel1), 50m)
.SetDisplay("CCI Level1", "Lower CCI for buys", "Trading");
_cciLevel2 = Param(nameof(CciLevel2), 190m)
.SetDisplay("CCI Level2", "Upper CCI for buys", "Trading");
_cciLevel3 = Param(nameof(CciLevel3), -50m)
.SetDisplay("CCI Level3", "Upper CCI for sells", "Trading");
_cciLevel4 = Param(nameof(CciLevel4), -190m)
.SetDisplay("CCI Level4", "Lower CCI for sells", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevVolume = 0;
_prevPrevVolume = 0;
_prevOpen = 0;
_prevClose = 0;
_longStop = 0;
_shortStop = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var cci = new CommodityChannelIndex { Length = 14 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(cci, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, cci);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue)
{
if (candle.State != CandleStates.Finished)
return;
var currentVolume = candle.TotalVolume;
{
var trailDist = TrailingStop;
var volumeOk = _prevVolume > _prevPrevVolume * Factor;
if (volumeOk)
{
if (_prevClose > _prevOpen && cciValue > CciLevel1 && cciValue < CciLevel2 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_longStop = candle.ClosePrice - trailDist;
_shortStop = 0m;
}
else if (_prevClose < _prevOpen && cciValue < CciLevel3 && cciValue > CciLevel4 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_shortStop = candle.ClosePrice + trailDist;
_longStop = 0m;
}
}
if (Position > 0)
{
var candidate = candle.ClosePrice - trailDist;
if (candidate > _longStop)
_longStop = candidate;
if (candle.ClosePrice <= _longStop)
{
SellMarket();
_longStop = 0m;
}
}
else if (Position < 0)
{
var candidate = candle.ClosePrice + trailDist;
if (_shortStop == 0m || candidate < _shortStop)
_shortStop = candidate;
if (candle.ClosePrice >= _shortStop)
{
BuyMarket();
_shortStop = 0m;
}
}
}
_prevPrevVolume = _prevVolume;
_prevVolume = currentVolume;
_prevOpen = candle.OpenPrice;
_prevClose = candle.ClosePrice;
}
}
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 CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class volume_ea_strategy(Strategy):
def __init__(self):
super(volume_ea_strategy, self).__init__()
self._factor = self.Param("Factor", 1.55) \
.SetDisplay("Factor", "Volume multiplier", "Trading")
self._trailing_stop = self.Param("TrailingStop", 350.0) \
.SetDisplay("Trailing Stop", "Trailing distance in steps", "Risk")
self._cci_level1 = self.Param("CciLevel1", 50) \
.SetDisplay("CCI Level1", "Lower CCI for buys", "Trading")
self._cci_level2 = self.Param("CciLevel2", 190) \
.SetDisplay("CCI Level2", "Upper CCI for buys", "Trading")
self._cci_level3 = self.Param("CciLevel3", -50) \
.SetDisplay("CCI Level3", "Upper CCI for sells", "Trading")
self._cci_level4 = self.Param("CciLevel4", -190.0) \
.SetDisplay("CCI Level4", "Lower CCI for sells", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._prev_volume = 0.0
self._prev_prev_volume = 0.0
self._prev_open = 0.0
self._prev_close = 0.0
self._long_stop = 0.0
self._short_stop = 0.0
@property
def factor(self):
return self._factor.Value
@property
def trailing_stop(self):
return self._trailing_stop.Value
@property
def cci_level1(self):
return self._cci_level1.Value
@property
def cci_level2(self):
return self._cci_level2.Value
@property
def cci_level3(self):
return self._cci_level3.Value
@property
def cci_level4(self):
return self._cci_level4.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(volume_ea_strategy, self).OnReseted()
self._prev_volume = 0.0
self._prev_prev_volume = 0.0
self._prev_open = 0.0
self._prev_close = 0.0
self._long_stop = 0.0
self._short_stop = 0.0
def OnStarted2(self, time):
super(volume_ea_strategy, self).OnStarted2(time)
cci = CommodityChannelIndex()
cci.Length = 14
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(cci, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, cci)
self.DrawOwnTrades(area)
def on_process(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
current_volume = candle.TotalVolume
trail_dist = self.trailing_stop
volume_ok = self._prev_volume > self._prev_prev_volume * self.factor
if volume_ok:
if self._prev_close > self._prev_open and cci_value > self.cci_level1 and cci_value < self.cci_level2 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._long_stop = candle.ClosePrice - trail_dist
self._short_stop = 0
elif self._prev_close < self._prev_open and cci_value < self.cci_level3 and cci_value > self.cci_level4 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._short_stop = candle.ClosePrice + trail_dist
self._long_stop = 0
if self.Position > 0:
candidate = candle.ClosePrice - trail_dist
if candidate > self._long_stop:
self._long_stop = candidate
if candle.ClosePrice <= self._long_stop:
self.SellMarket()
self._long_stop = 0
elif self.Position < 0:
candidate = candle.ClosePrice + trail_dist
if self._short_stop == 0 or candidate < self._short_stop:
self._short_stop = candidate
if candle.ClosePrice >= self._short_stop:
self.BuyMarket()
self._short_stop = 0
self._prev_prev_volume = self._prev_volume
self._prev_volume = current_volume
self._prev_open = candle.OpenPrice
self._prev_close = candle.ClosePrice
def CreateClone(self):
return volume_ea_strategy()