Gann Swing Breakout 戦略
Gannスイングブレイクアウト手法に基づく戦略
テストでは年平均リターンが約82%であることが示されています。株式市場で最もよく機能します。
Gann Swing Breakoutはガン分析によるスイング高値と安値を追跡します。最新のスイングを超えるブレイクアウトがその方向への取引を開始し、反対のスイングが破られるまでポジションを維持します。
この手法は過去のスイングポイントを重要なサポートとレジスタンスと見なすトレーダー向けに設計されています。ブレイクで取引することにより、トレンドの次の局面に乗ることを試みます。
詳細
- エントリー条件: MA、Gannに基づくシグナル。
- ロング/ショート: 両方向。
- エグジット条件: 逆シグナル。
- ストップ: いいえ。
- デフォルト値:
SwingLookback= 5MaPeriod= 20CandleType= TimeSpan.FromMinutes(15)
- フィルター:
- カテゴリ: ブレイクアウト
- 方向: 両方
- インジケーター: MA、Gann
- ストップ: いいえ
- 複雑さ: 基本
- 時間軸: イントラデイ (15m)
- 季節性: いいえ
- Neural Networks: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
using System;
using System.Linq;
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>
/// Strategy based on Gann Swing Breakout technique.
/// A swing high is a candle whose high exceeds the highs of SwingLookback candles on each side, a swing low the reverse.
/// A close above the latest swing high while above the SMA opens a long position, a close below the latest swing low
/// while below the SMA a short one. A position stays open until the opposing swing is breached.
/// </summary>
public class GannSwingBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _swingLookback;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly List<(decimal High, decimal Low)> _window = [];
private decimal? _swingHigh;
private decimal? _swingLow;
/// <summary>
/// Number of bars to identify swing points.
/// </summary>
public int SwingLookback
{
get => _swingLookback.Value;
set => _swingLookback.Value = value;
}
/// <summary>
/// Period for moving average calculation.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the Gann Swing Breakout strategy.
/// </summary>
public GannSwingBreakoutStrategy()
{
_swingLookback = Param(nameof(SwingLookback), 5)
.SetGreaterThanZero()
.SetDisplay("Swing Lookback", "Lookback period for swing high/low", "Trading parameters")
.SetOptimize(20, 60, 10);
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period for trend filter MA", "Indicators")
.SetOptimize(40, 80, 10);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).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();
_window.Clear();
_swingHigh = null;
_swingLow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_window.Clear();
_swingHigh = null;
_swingLow = null;
var ma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue maValue)
{
if (candle.State != CandleStates.Finished)
return;
UpdateSwings(candle);
if (!maValue.IsFormed || _swingHigh is not decimal swingHigh || _swingLow is not decimal swingLow)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var ma = maValue.GetValue<decimal>();
var close = candle.ClosePrice;
if (close > swingHigh && close > ma && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (close < swingLow && close < ma && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
else if (Position > 0 && close < swingLow)
{
SellMarket(Position);
}
else if (Position < 0 && close > swingHigh)
{
BuyMarket(-Position);
}
}
private void UpdateSwings(ICandleMessage candle)
{
// A pivot is confirmed once SwingLookback candles have closed after it.
_window.Add((candle.HighPrice, candle.LowPrice));
var size = 2 * SwingLookback + 1;
if (_window.Count > size)
_window.RemoveAt(0);
if (_window.Count < size)
return;
var pivot = _window[SwingLookback];
var others = _window.Where((_, index) => index != SwingLookback).ToArray();
if (others.All(c => pivot.High > c.High))
_swingHigh = pivot.High;
if (others.All(c => pivot.Low < c.Low))
_swingLow = pivot.Low;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class gann_swing_breakout_strategy(Strategy):
"""
Gann Swing Breakout.
A swing high is a candle whose high exceeds the highs of SwingLookback candles on each side, a swing low the reverse.
A close above the latest swing high while above the SMA opens a long position, a close below the latest swing low
while below the SMA a short one. A position stays open until the opposing swing is breached.
"""
def __init__(self):
super(gann_swing_breakout_strategy, self).__init__()
self._swing_lookback = self.Param("SwingLookback", 5) \
.SetGreaterThanZero() \
.SetDisplay("Swing Lookback", "Lookback period for swing high/low", "Trading parameters")
self._ma_period = self.Param("MaPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("MA Period", "Period for trend filter MA", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._window = []
self._swing_high = None
self._swing_low = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(gann_swing_breakout_strategy, self).OnReseted()
self._window = []
self._swing_high = None
self._swing_low = None
def OnStarted2(self, time):
super(gann_swing_breakout_strategy, self).OnStarted2(time)
self._window = []
self._swing_high = None
self._swing_low = None
ma = SimpleMovingAverage()
ma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
self._update_swings(candle)
if not ma_value.IsFormed or self._swing_high is None or self._swing_low is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
ma = ma_value.GetValue[Decimal](None)
close = candle.ClosePrice
position = self.Position
if close > self._swing_high and close > ma and position <= 0:
self.BuyMarket(self.Volume + Math.Abs(position))
elif close < self._swing_low and close < ma and position >= 0:
self.SellMarket(self.Volume + Math.Abs(position))
elif position > 0 and close < self._swing_low:
self.SellMarket(position)
elif position < 0 and close > self._swing_high:
self.BuyMarket(-position)
def _update_swings(self, candle):
# A pivot is confirmed once SwingLookback candles have closed after it.
lookback = self._swing_lookback.Value
self._window.append((candle.HighPrice, candle.LowPrice))
size = 2 * lookback + 1
if len(self._window) > size:
self._window.pop(0)
if len(self._window) < size:
return
pivot_high, pivot_low = self._window[lookback]
others = self._window[:lookback] + self._window[lookback + 1:]
if all(pivot_high > high for high, _ in others):
self._swing_high = pivot_high
if all(pivot_low < low for _, low in others):
self._swing_low = pivot_low
def CreateClone(self):
return gann_swing_breakout_strategy()