高低点策略
基于最高价和最低价区间的策略。
当当前K线中点低于最高价和最低价平均值且归一化距离低于 LowThreshold 时买入。当中点高于平均值且归一化距离超过 HighThreshold 时平仓。
详情
- 入场条件:中点低于平均值且归一化距离低于 LowThreshold。
- 多/空:仅做多。
- 出场条件:中点高于平均值且归一化距离高于 HighThreshold。
- 止损:无。
- 默认值:
Range= 100LowThreshold= 15mHighThreshold= 85mCandleType= TimeSpan.FromMinutes(240)
- 筛选器:
- 类别:区间
- 方向:做多
- 指标:Highest, Lowest
- 止损:无
- 复杂度:基础
- 时间框架:日内 (240m)
- 季节性:无
- 神经网络:无
- 背离:无
- 风险等级:中等
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;
/// <summary>
/// Highs Lows strategy.
/// Tracks the highest high and lowest low of the last Range candles. The candle midpoint is compared with the average of
/// these extremes, and their distance is normalized by half the range (0 at the average, 100 at an extreme). A long opens when the midpoint is
/// below the average and the normalized distance is below LowThreshold, and closes when the midpoint is above the average
/// and the normalized distance is above HighThreshold.
/// </summary>
public class HighsLowsStrategy : Strategy
{
private readonly StrategyParam<int> _range;
private readonly StrategyParam<decimal> _lowThreshold;
private readonly StrategyParam<decimal> _highThreshold;
private readonly StrategyParam<DataType> _candleType;
private Highest _highest;
private Lowest _lowest;
/// <summary>
/// Number of candles for the highest and lowest values.
/// </summary>
public int Range
{
get => _range.Value;
set => _range.Value = value;
}
/// <summary>
/// Normalized distance below which a long opens.
/// </summary>
public decimal LowThreshold
{
get => _lowThreshold.Value;
set => _lowThreshold.Value = value;
}
/// <summary>
/// Normalized distance above which the long closes.
/// </summary>
public decimal HighThreshold
{
get => _highThreshold.Value;
set => _highThreshold.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public HighsLowsStrategy()
{
_range = Param(nameof(Range), 100)
.SetGreaterThanZero()
.SetDisplay("Range", "Number of candles for highest and lowest values", "Indicators");
_lowThreshold = Param(nameof(LowThreshold), 15m)
.SetDisplay("Low Threshold", "Normalized distance below which a long opens", "Signals");
_highThreshold = Param(nameof(HighThreshold), 85m)
.SetDisplay("High Threshold", "Normalized distance above which the long closes", "Signals");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(240).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_highest = null;
_lowest = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highest = new Highest { Length = Range };
_lowest = new Lowest { Length = Range };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _highest);
DrawIndicator(area, _lowest);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var highest = _highest.Process(candle.HighPrice, candle.OpenTime, true).ToDecimal();
var lowest = _lowest.Process(candle.LowPrice, candle.OpenTime, true).ToDecimal();
if (!_highest.IsFormed || !_lowest.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var width = highest - lowest;
if (width <= 0)
return;
var midpoint = (candle.HighPrice + candle.LowPrice) / 2;
var average = (highest + lowest) / 2;
// Distance from the average as a percentage of the half range: 0 at the average, 100 at an extreme.
var distance = Math.Abs(midpoint - average) / (width / 2) * 100m;
if (Position <= 0 && midpoint < average && distance < LowThreshold)
BuyMarket(Volume + Math.Abs(Position));
else if (Position > 0 && midpoint > average && distance > HighThreshold)
SellMarket(Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class highs_lows_strategy(Strategy):
"""
Highs Lows strategy.
Tracks the highest high and lowest low of the last Range candles. The candle midpoint is compared with the average of
these extremes, and their distance is normalized by half the range (0 at the average, 100 at an extreme). A long opens when the midpoint is
below the average and the normalized distance is below LowThreshold, and closes when the midpoint is above the average
and the normalized distance is above HighThreshold.
"""
def __init__(self):
super(highs_lows_strategy, self).__init__()
self._range = self.Param("Range", 100).SetGreaterThanZero().SetDisplay("Range", "Number of candles for highest and lowest values", "Indicators")
self._low_threshold = self.Param("LowThreshold", 15.0).SetDisplay("Low Threshold", "Normalized distance below which a long opens", "Signals")
self._high_threshold = self.Param("HighThreshold", 85.0).SetDisplay("High Threshold", "Normalized distance above which the long closes", "Signals")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(240))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._highest = None
self._lowest = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(highs_lows_strategy, self).OnReseted()
self._highest = None
self._lowest = None
def OnStarted2(self, time):
super(highs_lows_strategy, self).OnStarted2(time)
self._highest = Highest()
self._highest.Length = self._range.Value
self._lowest = Lowest()
self._lowest.Length = self._range.Value
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.DrawIndicator(area, self._highest)
self.DrawIndicator(area, self._lowest)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
highest = process_float(self._highest, candle.HighPrice, candle.OpenTime, True).GetValue[Decimal](None)
lowest = process_float(self._lowest, candle.LowPrice, candle.OpenTime, True).GetValue[Decimal](None)
if not self._highest.IsFormed or not self._lowest.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
width = highest - lowest
if width <= 0:
return
midpoint = (candle.HighPrice + candle.LowPrice) / Decimal(2)
average = (highest + lowest) / Decimal(2)
# Distance from the average as a percentage of the half range: 0 at the average, 100 at an extreme.
distance = abs(midpoint - average) / (width / Decimal(2)) * Decimal(100)
if self.Position <= 0 and midpoint < average and distance < Decimal(self._low_threshold.Value):
self.BuyMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and midpoint > average and distance > Decimal(self._high_threshold.Value):
self.SellMarket(self.Position)
def CreateClone(self):
return highs_lows_strategy()