I4 DRF 策略
该策略基于自定义 I4 DRF 指标。它比较最近蜡烛的高点和低点方向并生成 -100 到 +100 之间的值。交易动作取决于指标颜色的变化以及所选模式。
细节
- 入场条件:
Direct模式:指标从正变负时做多,从负变正时做空。NotDirect模式:指标从负变正时做多,从正变负时做空。
- 方向:双向
- 出场条件:
- 当出现反向信号时平仓。
- 止损:无
- 默认值:
Period= 11SignalBar= 1TrendMode= DirectCandleType= TimeSpan.FromHours(4).TimeFrame()
- 筛选:
- 类型:趋势
- 方向:双向
- 指标:I4 DRF
- 止损:否
- 复杂度:基础
- 时间框架:中期
- 季节性:否
- 神经网络:否
- 背离:否
- 风险等级:中等
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 the I4 DRF indicator.
/// The indicator compares changes in highs and lows and returns a value between -100 and 100.
/// Depending on <see cref="TrendMode"/> signals are interpreted with or against the trend.
/// </summary>
public class I4DrfStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private readonly StrategyParam<int> _signalBar;
private readonly StrategyParam<Modes> _trendMode;
private readonly StrategyParam<bool> _buyPosOpen;
private readonly StrategyParam<bool> _sellPosOpen;
private readonly StrategyParam<bool> _buyPosClose;
private readonly StrategyParam<bool> _sellPosClose;
private I4Drf _indicator;
private decimal _prevColor;
private decimal _prevPrevColor;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public int SignalBar { get => _signalBar.Value; set => _signalBar.Value = value; }
public Modes TrendMode { get => _trendMode.Value; set => _trendMode.Value = value; }
public bool BuyPosOpen { get => _buyPosOpen.Value; set => _buyPosOpen.Value = value; }
public bool SellPosOpen { get => _sellPosOpen.Value; set => _sellPosOpen.Value = value; }
public bool BuyPosClose { get => _buyPosClose.Value; set => _buyPosClose.Value = value; }
public bool SellPosClose { get => _sellPosClose.Value; set => _sellPosClose.Value = value; }
public I4DrfStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe of candles", "General");
_period = Param(nameof(Period), 11)
.SetGreaterThanZero()
.SetDisplay("Period", "Indicator period", "Parameters");
_signalBar = Param(nameof(SignalBar), 1)
.SetGreaterThanZero()
.SetDisplay("Signal Bar", "Shift for signal", "Parameters");
_trendMode = Param(nameof(TrendMode), Modes.Direct)
.SetDisplay("Trend Modes", "Trading mode", "Parameters");
_buyPosOpen = Param(nameof(BuyPosOpen), true)
.SetDisplay("Open Long", "Allow opening long positions", "Switches");
_sellPosOpen = Param(nameof(SellPosOpen), true)
.SetDisplay("Open Short", "Allow opening short positions", "Switches");
_buyPosClose = Param(nameof(BuyPosClose), true)
.SetDisplay("Close Long", "Allow closing long positions", "Switches");
_sellPosClose = Param(nameof(SellPosClose), true)
.SetDisplay("Close Short", "Allow closing short positions", "Switches");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevColor = 0m;
_prevPrevColor = 0m;
_indicator?.Reset();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_indicator = new I4Drf { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_indicator, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _indicator);
DrawOwnTrades(area);
}
StartProtection(null, null);
}
private void ProcessCandle(ICandleMessage candle, decimal value)
{
if (candle.State != CandleStates.Finished)
return;
var color = value > 0m ? 1m : 0m;
if (!_indicator.IsFormed)
{
_prevPrevColor = _prevColor;
_prevColor = color;
return;
}
var buyOpen = false;
var sellOpen = false;
var buyClose = false;
var sellClose = false;
if (TrendMode == Modes.Direct)
{
if (_prevPrevColor == 1m)
{
if (BuyPosOpen && _prevColor < 1m)
buyOpen = true;
if (SellPosClose)
sellClose = true;
}
if (_prevPrevColor == 0m)
{
if (SellPosOpen && _prevColor > 0m)
sellOpen = true;
if (BuyPosClose)
buyClose = true;
}
}
else
{
if (_prevPrevColor == 0m)
{
if (BuyPosOpen && _prevColor > 0m)
buyOpen = true;
if (SellPosClose)
sellClose = true;
}
if (_prevPrevColor == 1m)
{
if (SellPosOpen && _prevColor < 1m)
sellOpen = true;
if (BuyPosClose)
buyClose = true;
}
}
if (buyClose && Position > 0)
SellMarket();
if (sellClose && Position < 0)
BuyMarket();
if (buyOpen && Position <= 0)
BuyMarket();
if (sellOpen && Position >= 0)
SellMarket();
_prevPrevColor = _prevColor;
_prevColor = color;
}
public enum Modes
{
Direct,
NotDirect
}
private class I4Drf : BaseIndicator
{
public int Length { get; set; } = 11;
private readonly Queue<int> _diffs = new();
private int _sum;
private decimal? _prevPrice;
protected override IIndicatorValue OnProcess(IIndicatorValue input)
{
var price = input.GetValue<decimal>();
if (_prevPrice is null)
{
_prevPrice = price;
IsFormed = false;
return new DecimalIndicatorValue(this, 0m, input.Time);
}
var diff = price > _prevPrice.Value ? 1 : (price < _prevPrice.Value ? -1 : 0);
_prevPrice = price;
_sum += diff;
_diffs.Enqueue(diff);
if (_diffs.Count > Length)
_sum -= _diffs.Dequeue();
if (_diffs.Count < Length)
{
IsFormed = false;
return new DecimalIndicatorValue(this, 0m, input.Time);
}
IsFormed = true;
var value = (decimal)_sum / Length * 100m;
return new DecimalIndicatorValue(this, value, input.Time);
}
public override void Reset()
{
base.Reset();
_diffs.Clear();
_sum = 0;
_prevPrice = null;
}
}
}
import clr
from collections import deque
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.Strategies import Strategy
MODE_DIRECT = 0
MODE_NOT_DIRECT = 1
class i4_drf_strategy(Strategy):
def __init__(self):
super(i4_drf_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe of candles", "General")
self._period = self.Param("Period", 11) \
.SetDisplay("Period", "Indicator period", "Parameters")
self._signal_bar = self.Param("SignalBar", 1) \
.SetDisplay("Signal Bar", "Shift for signal", "Parameters")
self._trend_mode = self.Param("TrendMode", 0) \
.SetDisplay("Trend Mode", "0=Direct, 1=NotDirect", "Parameters")
self._buy_pos_open = self.Param("BuyPosOpen", True) \
.SetDisplay("Open Long", "Allow opening long positions", "Switches")
self._sell_pos_open = self.Param("SellPosOpen", True) \
.SetDisplay("Open Short", "Allow opening short positions", "Switches")
self._buy_pos_close = self.Param("BuyPosClose", True) \
.SetDisplay("Close Long", "Allow closing long positions", "Switches")
self._sell_pos_close = self.Param("SellPosClose", True) \
.SetDisplay("Close Short", "Allow closing short positions", "Switches")
self._diffs = deque()
self._sum = 0
self._prev_price = None
self._is_formed = False
self._prev_color = 0.0
self._prev_prev_color = 0.0
@property
def candle_type(self):
return self._candle_type.Value
@property
def period(self):
return self._period.Value
@property
def signal_bar(self):
return self._signal_bar.Value
@property
def trend_mode(self):
return self._trend_mode.Value
@property
def buy_pos_open(self):
return self._buy_pos_open.Value
@property
def sell_pos_open(self):
return self._sell_pos_open.Value
@property
def buy_pos_close(self):
return self._buy_pos_close.Value
@property
def sell_pos_close(self):
return self._sell_pos_close.Value
def OnReseted(self):
super(i4_drf_strategy, self).OnReseted()
self._diffs = deque()
self._sum = 0
self._prev_price = None
self._is_formed = False
self._prev_color = 0.0
self._prev_prev_color = 0.0
def OnStarted2(self, time):
super(i4_drf_strategy, self).OnStarted2(time)
self._diffs = deque()
self._sum = 0
self._prev_price = None
self._is_formed = False
self._prev_color = 0.0
self._prev_prev_color = 0.0
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _compute_i4drf(self, price):
length = int(self.period)
if self._prev_price is None:
self._prev_price = price
self._is_formed = False
return 0.0
if price > self._prev_price:
diff = 1
elif price < self._prev_price:
diff = -1
else:
diff = 0
self._prev_price = price
self._sum += diff
self._diffs.append(diff)
if len(self._diffs) > length:
self._sum -= self._diffs.popleft()
if len(self._diffs) < length:
self._is_formed = False
return 0.0
self._is_formed = True
return float(self._sum) / length * 100.0
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
value = self._compute_i4drf(price)
color = 1.0 if value > 0 else 0.0
if not self._is_formed:
self._prev_prev_color = self._prev_color
self._prev_color = color
return
buy_open = False
sell_open = False
buy_close = False
sell_close = False
tm = int(self.trend_mode)
if tm == MODE_DIRECT:
if self._prev_prev_color == 1.0:
if self.buy_pos_open and self._prev_color < 1.0:
buy_open = True
if self.sell_pos_close:
sell_close = True
if self._prev_prev_color == 0.0:
if self.sell_pos_open and self._prev_color > 0.0:
sell_open = True
if self.buy_pos_close:
buy_close = True
else:
if self._prev_prev_color == 0.0:
if self.buy_pos_open and self._prev_color > 0.0:
buy_open = True
if self.sell_pos_close:
sell_close = True
if self._prev_prev_color == 1.0:
if self.sell_pos_open and self._prev_color < 1.0:
sell_open = True
if self.buy_pos_close:
buy_close = True
if buy_close and self.Position > 0:
self.SellMarket()
if sell_close and self.Position < 0:
self.BuyMarket()
if buy_open and self.Position <= 0:
self.BuyMarket()
if sell_open and self.Position >= 0:
self.SellMarket()
self._prev_prev_color = self._prev_color
self._prev_color = color
def CreateClone(self):
return i4_drf_strategy()