ゴールド ORB 戦略
この戦略はアジアセッションの高値と安値を記録し、その後の時間帯にブレイクアウトを取引します。ストップと目標は、レンジサイズと報酬乗数から算出されます。
詳細
- エントリー条件:
- トレードウィンドウ中、価格が記録されたアジアの高値を上回って終値をつけたときにロング。
- 価格が記録されたアジアの安値を下回って終値をつけたときにショート。
- ロング/ショート: 両方
- エグジット条件:
- レンジサイズと報酬乗数に基づくストップと目標。
- ストップ: はい
- デフォルト値:
AsiaStart= 00:00AsiaEnd= 06:00TradeStart= 06:00TradeEnd= 10:00RewardMultiplier= 2.0
- フィルター:
- カテゴリ: ブレイクアウト
- 方向: 両方
- インジケーター: なし
- ストップ: はい
- 複雑さ: 低
- 時間軸: 5m
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Gold opening range breakout strategy.
/// The high and low of the candles opening between AsiaStart and AsiaEnd (UTC) form the Asia range of the day. Between TradeStart and
/// TradeEnd a close above the range high goes long and a close below the range low goes short. The stop is one range size away from the
/// entry and the target RewardMultiplier range sizes away.
/// </summary>
public class GoldOrbStrategy : Strategy
{
private readonly StrategyParam<TimeSpan> _asiaStart;
private readonly StrategyParam<TimeSpan> _asiaEnd;
private readonly StrategyParam<TimeSpan> _tradeStart;
private readonly StrategyParam<TimeSpan> _tradeEnd;
private readonly StrategyParam<decimal> _rewardMultiplier;
private readonly StrategyParam<DataType> _candleType;
private DateTime? _rangeDay;
private decimal? _asiaHigh;
private decimal? _asiaLow;
private decimal _stopPrice;
private decimal _takePrice;
/// <summary>
/// Start of the Asia session (UTC).
/// </summary>
public TimeSpan AsiaStart
{
get => _asiaStart.Value;
set => _asiaStart.Value = value;
}
/// <summary>
/// End of the Asia session (UTC).
/// </summary>
public TimeSpan AsiaEnd
{
get => _asiaEnd.Value;
set => _asiaEnd.Value = value;
}
/// <summary>
/// Start of the trade window (UTC).
/// </summary>
public TimeSpan TradeStart
{
get => _tradeStart.Value;
set => _tradeStart.Value = value;
}
/// <summary>
/// End of the trade window (UTC).
/// </summary>
public TimeSpan TradeEnd
{
get => _tradeEnd.Value;
set => _tradeEnd.Value = value;
}
/// <summary>
/// Target distance in range sizes.
/// </summary>
public decimal RewardMultiplier
{
get => _rewardMultiplier.Value;
set => _rewardMultiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public GoldOrbStrategy()
{
_asiaStart = Param(nameof(AsiaStart), TimeSpan.Zero)
.SetDisplay("Asia Start", "Start of the Asia session (UTC)", "Session");
_asiaEnd = Param(nameof(AsiaEnd), TimeSpan.FromHours(6))
.SetDisplay("Asia End", "End of the Asia session (UTC)", "Session");
_tradeStart = Param(nameof(TradeStart), TimeSpan.FromHours(6))
.SetDisplay("Trade Start", "Start of the trade window (UTC)", "Session");
_tradeEnd = Param(nameof(TradeEnd), TimeSpan.FromHours(10))
.SetDisplay("Trade End", "End of the trade window (UTC)", "Session");
_rewardMultiplier = Param(nameof(RewardMultiplier), 2.0m)
.SetGreaterThanZero()
.SetDisplay("Reward Multiplier", "Target distance in range sizes", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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()
{
_rangeDay = null;
_asiaHigh = null;
_asiaLow = null;
_stopPrice = 0m;
_takePrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var day = candle.OpenTime.Date;
var timeOfDay = candle.OpenTime.TimeOfDay;
if (_rangeDay != day)
{
_rangeDay = day;
_asiaHigh = null;
_asiaLow = null;
}
if (timeOfDay >= AsiaStart && timeOfDay < AsiaEnd)
{
_asiaHigh = _asiaHigh is decimal h ? Math.Max(h, candle.HighPrice) : candle.HighPrice;
_asiaLow = _asiaLow is decimal l ? Math.Min(l, candle.LowPrice) : candle.LowPrice;
}
if (ManagePosition(candle))
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position != 0 || timeOfDay < TradeStart || timeOfDay >= TradeEnd)
return;
if (_asiaHigh is not decimal high || _asiaLow is not decimal low)
return;
var range = high - low;
if (range <= 0)
return;
var close = candle.ClosePrice;
if (close > high)
{
BuyMarket(Volume);
_stopPrice = close - range;
_takePrice = close + range * RewardMultiplier;
}
else if (close < low)
{
SellMarket(Volume);
_stopPrice = close + range;
_takePrice = close - range * RewardMultiplier;
}
}
// Returns true when the position was closed on this candle.
private bool ManagePosition(ICandleMessage candle)
{
if (Position > 0 && _stopPrice > 0)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
{
SellMarket(Position);
return true;
}
}
else if (Position < 0 && _stopPrice > 0)
{
if (candle.HighPrice >= _stopPrice || candle.LowPrice <= _takePrice)
{
BuyMarket(Math.Abs(Position));
return true;
}
}
return false;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class gold_orb_strategy(Strategy):
"""
Gold opening range breakout strategy.
The high and low of the candles opening between AsiaStart and AsiaEnd (UTC) form the Asia range of the day. Between TradeStart and
TradeEnd a close above the range high goes long and a close below the range low goes short. The stop is one range size away from the
entry and the target RewardMultiplier range sizes away.
"""
def __init__(self):
super(gold_orb_strategy, self).__init__()
self._asia_start = self.Param("AsiaStart", TimeSpan.Zero).SetDisplay("Asia Start", "Start of the Asia session (UTC)", "Session")
self._asia_end = self.Param("AsiaEnd", TimeSpan.FromHours(6)).SetDisplay("Asia End", "End of the Asia session (UTC)", "Session")
self._trade_start = self.Param("TradeStart", TimeSpan.FromHours(6)).SetDisplay("Trade Start", "Start of the trade window (UTC)", "Session")
self._trade_end = self.Param("TradeEnd", TimeSpan.FromHours(10)).SetDisplay("Trade End", "End of the trade window (UTC)", "Session")
self._reward_multiplier = self.Param("RewardMultiplier", 2.0).SetGreaterThanZero().SetDisplay("Reward Multiplier", "Target distance in range sizes", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).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._range_day = None
self._asia_high = None
self._asia_low = None
self._stop_price = Decimal(0)
self._take_price = Decimal(0)
def OnReseted(self):
super(gold_orb_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(gold_orb_strategy, self).OnStarted2(time)
self._reset_state()
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 _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
day = candle.OpenTime.Date
time_of_day = candle.OpenTime.TimeOfDay
if self._range_day is None or self._range_day != day:
self._range_day = day
self._asia_high = None
self._asia_low = None
if self._asia_start.Value <= time_of_day < self._asia_end.Value:
self._asia_high = candle.HighPrice if self._asia_high is None else Math.Max(self._asia_high, candle.HighPrice)
self._asia_low = candle.LowPrice if self._asia_low is None else Math.Min(self._asia_low, candle.LowPrice)
if self._manage_position(candle):
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position != 0 or time_of_day < self._trade_start.Value or time_of_day >= self._trade_end.Value:
return
if self._asia_high is None or self._asia_low is None:
return
high = self._asia_high
low = self._asia_low
rng = high - low
if rng <= 0:
return
close = candle.ClosePrice
multiplier = Decimal(self._reward_multiplier.Value)
if close > high:
self.BuyMarket(self.Volume)
self._stop_price = close - rng
self._take_price = close + rng * multiplier
elif close < low:
self.SellMarket(self.Volume)
self._stop_price = close + rng
self._take_price = close - rng * multiplier
def _manage_position(self, candle):
if self.Position > 0 and self._stop_price > 0:
if candle.LowPrice <= self._stop_price or candle.HighPrice >= self._take_price:
self.SellMarket(self.Position)
return True
elif self.Position < 0 and self._stop_price > 0:
if candle.HighPrice >= self._stop_price or candle.LowPrice <= self._take_price:
self.BuyMarket(abs(self.Position))
return True
return False
def CreateClone(self):
return gold_orb_strategy()