Fibonacci スイングトレーディングボット
Fibonacciリトレースメントレベルを使用してスイング動向を取引する戦略。
このボットは直近50バーのレンジから0.618と0.786のリトレースメントレベルを計算し、ローソク足がこれらのレベルを上下にブレイクアウトしたときにポジションを開きます。リスク管理は設定可能なストップロスとリスク/リワード比パラメータで行います。
詳細
- エントリー条件: FibonacciレベルによるPrice Action。
- ロング/ショート: 両方向。
- エグジット条件: ストップロスまたはテイクプロフィット。
- ストップ: はい、パーセントベース。
- デフォルト値:
FiboLevel1= 0.618FiboLevel2= 0.786RiskRewardRatio= 2StopLossPercent= 1CandleType= TimeSpan.FromHours(4)
- フィルター:
- カテゴリ: スイング
- 方向: 両方
- インジケーター: Fibonacci, Donchian
- ストップ: はい
- 複雑さ: 中級
- 時間軸: 4h
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Fibonacci Swing Trading Bot strategy.
/// Retracement levels FiboLevel1 and FiboLevel2 are measured down from the highest high of the last 50 candles towards the
/// lowest low. A close breaking above the FiboLevel1 level goes long and a close breaking below the FiboLevel2 level goes short,
/// reversing an opposite position. Each position is protected by a percent stop loss and a take profit RiskRewardRatio times
/// further away.
/// </summary>
public class FibonacciSwingTradingBotStrategy : Strategy
{
private const int _rangeLength = 50;
private readonly StrategyParam<decimal> _fiboLevel1;
private readonly StrategyParam<decimal> _fiboLevel2;
private readonly StrategyParam<decimal> _riskRewardRatio;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevClose;
private decimal? _prevLevel1;
private decimal? _prevLevel2;
/// <summary>
/// Retracement ratio of the level whose upward break goes long.
/// </summary>
public decimal FiboLevel1
{
get => _fiboLevel1.Value;
set => _fiboLevel1.Value = value;
}
/// <summary>
/// Retracement ratio of the level whose downward break goes short.
/// </summary>
public decimal FiboLevel2
{
get => _fiboLevel2.Value;
set => _fiboLevel2.Value = value;
}
/// <summary>
/// Take profit distance as a multiple of the stop distance.
/// </summary>
public decimal RiskRewardRatio
{
get => _riskRewardRatio.Value;
set => _riskRewardRatio.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public FibonacciSwingTradingBotStrategy()
{
_fiboLevel1 = Param(nameof(FiboLevel1), 0.618m)
.SetDisplay("Fibo Level 1", "Retracement ratio of the long breakout level", "Fibonacci");
_fiboLevel2 = Param(nameof(FiboLevel2), 0.786m)
.SetDisplay("Fibo Level 2", "Retracement ratio of the short breakout level", "Fibonacci");
_riskRewardRatio = Param(nameof(RiskRewardRatio), 2m)
.SetNotNegative()
.SetDisplay("Risk/Reward", "Take profit distance as a multiple of the stop distance", "Risk");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
ResetState();
}
private void ResetState()
{
_prevClose = null;
_prevLevel1 = null;
_prevLevel2 = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var highest = new Highest { Length = _rangeLength };
var lowest = new Lowest { Length = _rangeLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
StartProtection(
new Unit(StopLossPercent * RiskRewardRatio, UnitTypes.Percent),
new Unit(StopLossPercent, UnitTypes.Percent),
useMarketOrders: true,
isLocalStop: true);
// The stop and target have to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished)
return;
var range = high - low;
var level1 = high - range * FiboLevel1;
var level2 = high - range * FiboLevel2;
var prevClose = _prevClose;
var prevLevel1 = _prevLevel1;
var prevLevel2 = _prevLevel2;
_prevClose = candle.ClosePrice;
_prevLevel1 = level1;
_prevLevel2 = level2;
if (prevClose is not decimal lastClose || prevLevel1 is not decimal lastLevel1 || prevLevel2 is not decimal lastLevel2)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (lastClose <= lastLevel1 && close > level1 && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (lastClose >= lastLevel2 && close < level2 && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
RANGE_LENGTH = 50
class fibonacci_swing_trading_bot_strategy(Strategy):
"""
Fibonacci Swing Trading Bot strategy.
Retracement levels FiboLevel1 and FiboLevel2 are measured down from the highest high of the last 50 candles towards the
lowest low. A close breaking above the FiboLevel1 level goes long and a close breaking below the FiboLevel2 level goes short,
reversing an opposite position. Each position is protected by a percent stop loss and a take profit RiskRewardRatio times
further away.
"""
def __init__(self):
super(fibonacci_swing_trading_bot_strategy, self).__init__()
self._fibo_level1 = self.Param("FiboLevel1", 0.618).SetDisplay("Fibo Level 1", "Retracement ratio of the long breakout level", "Fibonacci")
self._fibo_level2 = self.Param("FiboLevel2", 0.786).SetDisplay("Fibo Level 2", "Retracement ratio of the short breakout level", "Fibonacci")
self._risk_reward_ratio = self.Param("RiskRewardRatio", 2.0).SetNotNegative().SetDisplay("Risk/Reward", "Take profit distance as a multiple of the stop distance", "Risk")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_close = None
self._prev_level1 = None
self._prev_level2 = None
def OnReseted(self):
super(fibonacci_swing_trading_bot_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(fibonacci_swing_trading_bot_strategy, self).OnStarted2(time)
self._reset_state()
highest = Highest()
highest.Length = RANGE_LENGTH
lowest = Lowest()
lowest.Length = RANGE_LENGTH
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self._process_candle).Start()
stop = float(self._stop_loss_percent.Value)
take = stop * float(self._risk_reward_ratio.Value)
self.StartProtection(Unit(Decimal(take), UnitTypes.Percent), Unit(Decimal(stop), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop and target have to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
high = float(high_value)
low = float(low_value)
rng = high - low
level1 = high - rng * float(self._fibo_level1.Value)
level2 = high - rng * float(self._fibo_level2.Value)
close = float(candle.ClosePrice)
last_close = self._prev_close
last_level1 = self._prev_level1
last_level2 = self._prev_level2
self._prev_close = close
self._prev_level1 = level1
self._prev_level2 = level2
if last_close is None or last_level1 is None or last_level2 is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if last_close <= last_level1 and close > level1 and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif last_close >= last_level2 and close < level2 and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return fibonacci_swing_trading_bot_strategy()