自适应CG振荡器X2策略
在两个不同的时间框上使用自适应CG振荡器。 较大的时间框确定整体趋势,较小的时间框根据振荡器交叉生成进出场信号。
细节
- 入场条件:
- 多头:在总体趋势向上时,主线向下穿过信号线
- 空头:在总体趋势向下时,主线上穿信号线
- 多空方向:双向
- 出场条件:反向信号或强制关闭标志
- 止损:无
- 默认值:
TrendAlpha= 0.07mSignalAlpha= 0.07mTrendCandleType= TimeSpan.FromHours(6).TimeFrame()SignalCandleType= TimeSpan.FromMinutes(30).TimeFrame()
- 过滤器:
- 分类:振荡器
- 方向:双向
- 指标:Adaptive CG Oscillator
- 止损:无
- 复杂度:中等
- 时间框:多时间框
- 季节性:无
- 神经网络:无
- 背离:无
- 风险等级:中等
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 Adaptive Center of Gravity Oscillator.
/// Computes CG oscillator inline and trades on crossovers of CG with its prior value (signal).
/// </summary>
public class AdaptiveCgOscillatorX2Strategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _prices = new();
private decimal _prevCg;
private decimal _prevPrevCg;
private int _count;
private int _barsSinceSignal;
public int Period { get => _period.Value; set => _period.Value = value; }
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AdaptiveCgOscillatorX2Strategy()
{
_period = Param(nameof(Period), 20)
.SetGreaterThanZero()
.SetDisplay("Period", "Lookback period for CG oscillator", "Parameters")
.SetOptimize(5, 20, 1);
_stopLoss = Param(nameof(StopLoss), 1000m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk");
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetGreaterThanZero()
.SetDisplay("Take Profit", "Take profit in price units", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prices.Clear();
_prevCg = 0m;
_prevPrevCg = 0m;
_count = 0;
_barsSinceSignal = int.MaxValue;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType)
.Bind(ProcessCandle)
.Start();
StartProtection(
new Unit(TakeProfit, UnitTypes.Absolute),
new Unit(StopLoss, UnitTypes.Absolute));
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var price = candle.ClosePrice;
_barsSinceSignal++;
_prices.Add(price);
if (_prices.Count > Period)
_prices.RemoveAt(0);
if (_prices.Count < Period)
return;
// Compute Center of Gravity
decimal num = 0m;
decimal denom = 0m;
for (int i = 0; i < _prices.Count; i++)
{
num += (1 + i) * _prices[i];
denom += _prices[i];
}
var cg = denom != 0 ? -num / denom + (Period + 1m) / 2m : 0m;
_count++;
if (_count < 3)
{
_prevPrevCg = _prevCg;
_prevCg = cg;
return;
}
var longSignal = cg > 0m && cg > _prevCg && _prevCg <= _prevPrevCg;
var shortSignal = cg < 0m && cg < _prevCg && _prevCg >= _prevPrevCg;
if (longSignal && _barsSinceSignal >= 12 && Position <= 0)
{
BuyMarket();
_barsSinceSignal = 0;
}
else if (shortSignal && _barsSinceSignal >= 12 && Position >= 0)
{
SellMarket();
_barsSinceSignal = 0;
}
_prevPrevCg = _prevCg;
_prevCg = cg;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class adaptive_cg_oscillator_x2_strategy(Strategy):
def __init__(self):
super(adaptive_cg_oscillator_x2_strategy, self).__init__()
self._period = self.Param("Period", 20)
self._stop_loss = self.Param("StopLoss", 1000.0)
self._take_profit = self.Param("TakeProfit", 2000.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._prices = []
self._prev_cg = 0.0
self._prev_prev_cg = 0.0
self._count = 0
self._bars_since_signal = 999999
@property
def Period(self):
return self._period.Value
@Period.setter
def Period(self, value):
self._period.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(adaptive_cg_oscillator_x2_strategy, self).OnStarted2(time)
self._prices = []
self._prev_cg = 0.0
self._prev_prev_cg = 0.0
self._count = 0
self._bars_since_signal = 999999
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
self.StartProtection(
Unit(self.TakeProfit, UnitTypes.Absolute),
Unit(self.StopLoss, UnitTypes.Absolute))
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
period = int(self.Period)
self._bars_since_signal += 1
self._prices.append(price)
if len(self._prices) > period:
self._prices.pop(0)
if len(self._prices) < period:
return
num = 0.0
denom = 0.0
for i in range(len(self._prices)):
num += (1 + i) * self._prices[i]
denom += self._prices[i]
if denom != 0.0:
cg = -num / denom + (period + 1.0) / 2.0
else:
cg = 0.0
self._count += 1
if self._count < 3:
self._prev_prev_cg = self._prev_cg
self._prev_cg = cg
return
long_signal = cg > 0.0 and cg > self._prev_cg and self._prev_cg <= self._prev_prev_cg
short_signal = cg < 0.0 and cg < self._prev_cg and self._prev_cg >= self._prev_prev_cg
if long_signal and self._bars_since_signal >= 12 and self.Position <= 0:
self.BuyMarket()
self._bars_since_signal = 0
elif short_signal and self._bars_since_signal >= 12 and self.Position >= 0:
self.SellMarket()
self._bars_since_signal = 0
self._prev_prev_cg = self._prev_cg
self._prev_cg = cg
def OnReseted(self):
super(adaptive_cg_oscillator_x2_strategy, self).OnReseted()
self._prices = []
self._prev_cg = 0.0
self._prev_prev_cg = 0.0
self._count = 0
self._bars_since_signal = 999999
def CreateClone(self):
return adaptive_cg_oscillator_x2_strategy()