XKRI Histogram 策略
该策略基于 Kairi Relative Index 指标,并使用指数移动平均进行平滑。系统在平滑后的振荡器出现局部高点或低点时识别反转模式并开仓做多或做空。
细节
- 入场条件:
- 做多:
Kri[1] < Kri[2] && Kri[0] > Kri[1] - 做空:
Kri[1] > Kri[2] && Kri[0] < Kri[1]
- 做多:
- 多空方向:双向
- 止损/止盈:按点数设定
- 默认值:
KriPeriod= 20SmoothPeriod= 7TakeProfit= 2000StopLoss= 1000CandleType= TimeSpan.FromHours(4).TimeFrame()
- 过滤器:
- 类别:反转
- 方向:双向
- 指标:Kairi、EMA
- 止损:是
- 复杂度:初级
- 时间框架:中期
- 季节性:否
- 神经网络:否
- 背离:否
- 风险等级:中等
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;
public class XkriHistogramStrategy : Strategy
{
private readonly StrategyParam<int> _kriPeriod;
private readonly StrategyParam<int> _smoothPeriod;
private readonly StrategyParam<decimal> _takeProfitPct;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _smooth;
private decimal _last;
private decimal _prev;
private decimal _prev2;
private int _valueCount;
public int KriPeriod { get => _kriPeriod.Value; set => _kriPeriod.Value = value; }
public int SmoothPeriod { get => _smoothPeriod.Value; set => _smoothPeriod.Value = value; }
public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public XkriHistogramStrategy()
{
_kriPeriod = Param(nameof(KriPeriod), 20)
.SetDisplay("KRI Period", "Base moving average period", "Indicators");
_smoothPeriod = Param(nameof(SmoothPeriod), 7)
.SetDisplay("Smooth Period", "EMA smoothing period", "Indicators");
_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
.SetDisplay("Take Profit %", "Take profit percentage", "Protection");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Protection");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_smooth = default;
_last = 0;
_prev = 0;
_prev2 = 0;
_valueCount = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ma = new ExponentialMovingAverage { Length = KriPeriod };
_smooth = new ExponentialMovingAverage { Length = SmoothPeriod };
Indicators.Add(_smooth);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ma, (candle, maValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (maValue == 0) return;
var kri = 100m * (candle.ClosePrice - maValue) / maValue;
var smoothResult = _smooth.Process(kri, candle.OpenTime, true);
if (!smoothResult.IsFormed)
return;
var smooth = smoothResult.ToDecimal();
_prev2 = _prev;
_prev = _last;
_last = smooth;
_valueCount++;
if (_valueCount < 3)
return;
var longSignal = _prev < _prev2 && _last > _prev && Position <= 0;
var shortSignal = _prev > _prev2 && _last < _prev && Position >= 0;
if (longSignal)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (shortSignal)
{
if (Position > 0) SellMarket();
SellMarket();
}
}).Start();
StartProtection(
takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _smooth);
DrawOwnTrades(area);
}
}
}
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.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class xkri_histogram_strategy(Strategy):
def __init__(self):
super(xkri_histogram_strategy, self).__init__()
self._kri_period = self.Param("KriPeriod", 20) \
.SetDisplay("KRI Period", "Base moving average period", "Indicators")
self._smooth_period = self.Param("SmoothPeriod", 7) \
.SetDisplay("Smooth Period", "EMA smoothing period", "Indicators")
self._take_profit_pct = self.Param("TakeProfitPct", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Protection")
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Protection")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame for candles", "General")
self._smooth = None
self._last = 0.0
self._prev = 0.0
self._prev2 = 0.0
self._value_count = 0
@property
def kri_period(self):
return self._kri_period.Value
@property
def smooth_period(self):
return self._smooth_period.Value
@property
def take_profit_pct(self):
return self._take_profit_pct.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(xkri_histogram_strategy, self).OnReseted()
self._smooth = None
self._last = 0.0
self._prev = 0.0
self._prev2 = 0.0
self._value_count = 0
def OnStarted2(self, time):
super(xkri_histogram_strategy, self).OnStarted2(time)
ma = ExponentialMovingAverage()
ma.Length = self.kri_period
self._smooth = ExponentialMovingAverage()
self._smooth.Length = self.smooth_period
self.Indicators.Add(self._smooth)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ma, self.on_candle).Start()
self.StartProtection(
takeProfit=Unit(self.take_profit_pct, UnitTypes.Percent),
stopLoss=Unit(self.stop_loss_pct, UnitTypes.Percent),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._smooth)
self.DrawOwnTrades(area)
def on_candle(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
if ma_value == 0:
return
kri = 100 * (candle.ClosePrice - ma_value) / ma_value
smooth_result = process_float(self._smooth, kri, candle.OpenTime, True)
if not smooth_result.IsFormed:
return
smooth = float(smooth_result)
self._prev2 = self._prev
self._prev = self._last
self._last = smooth
self._value_count += 1
if self._value_count < 3:
return
long_signal = self._prev < self._prev2 and self._last > self._prev and self.Position <= 0
short_signal = self._prev > self._prev2 and self._last < self._prev and self.Position >= 0
if long_signal:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif short_signal:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return xkri_histogram_strategy()