BTC季節性戦略
この戦略は、東部標準時(EST)の曜日と時間に基づく事前定義ルールに従ってポジションを建てます。ユーザーはエントリーの曜日・時間、エグジットの曜日・時間、ロングかショートかを選択します。ポジションは指定したエントリー時点で建てられ、指定したエグジット時点でクローズされます。
詳細
- エントリー条件:
- 現在のEST曜日が
EntryDayと等しく、現在の時間がEntryHourと等しい。
- 現在のEST曜日が
- ロング/ショート: 設定可能。
- エグジット条件:
- 現在のEST曜日が
ExitDayと等しく、現在の時間がExitHourと等しい。
- 現在のEST曜日が
- ストップ: なし。
- デフォルト値:
EntryDay= SaturdayExitDay= MondayEntryHour= 10ExitHour= 10IsLong= true
- フィルター:
- カテゴリ: 季節性
- 方向: 設定可能
- インジケーター: なし
- ストップ: いいえ
- 複雑さ: 低
- 時間軸: 任意
- 季節性: はい
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 低
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// BTC Seasonality strategy.
/// Opens a long (IsLong) or short position at the first candle of EntryHour on EntryDay and closes it at the first candle of
/// ExitHour on ExitDay. Days and hours are in Eastern Standard Time (UTC-5).
/// </summary>
public class BtcSeasonalityStrategy : Strategy
{
private static readonly TimeSpan _estOffset = TimeSpan.FromHours(-5);
private readonly StrategyParam<DayOfWeek> _entryDay;
private readonly StrategyParam<DayOfWeek> _exitDay;
private readonly StrategyParam<int> _entryHour;
private readonly StrategyParam<int> _exitHour;
private readonly StrategyParam<bool> _isLong;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// EST day of the entry.
/// </summary>
public DayOfWeek EntryDay
{
get => _entryDay.Value;
set => _entryDay.Value = value;
}
/// <summary>
/// EST day of the exit.
/// </summary>
public DayOfWeek ExitDay
{
get => _exitDay.Value;
set => _exitDay.Value = value;
}
/// <summary>
/// EST hour of the entry.
/// </summary>
public int EntryHour
{
get => _entryHour.Value;
set => _entryHour.Value = value;
}
/// <summary>
/// EST hour of the exit.
/// </summary>
public int ExitHour
{
get => _exitHour.Value;
set => _exitHour.Value = value;
}
/// <summary>
/// Trade long when true, short otherwise.
/// </summary>
public bool IsLong
{
get => _isLong.Value;
set => _isLong.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public BtcSeasonalityStrategy()
{
_entryDay = Param(nameof(EntryDay), DayOfWeek.Saturday)
.SetDisplay("Entry Day", "EST day of the entry", "Schedule");
_exitDay = Param(nameof(ExitDay), DayOfWeek.Monday)
.SetDisplay("Exit Day", "EST day of the exit", "Schedule");
_entryHour = Param(nameof(EntryHour), 10)
.SetRange(0, 23)
.SetDisplay("Entry Hour", "EST hour of the entry", "Schedule");
_exitHour = Param(nameof(ExitHour), 10)
.SetRange(0, 23)
.SetDisplay("Exit Hour", "EST hour of the exit", "Schedule");
_isLong = Param(nameof(IsLong), true)
.SetDisplay("Is Long", "Trade long when true, short otherwise", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).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 OnStarted2(DateTime time)
{
base.OnStarted2(time);
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;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var est = candle.OpenTime.Add(_estOffset);
if (Position != 0)
{
if (est.DayOfWeek == ExitDay && est.Hour == ExitHour)
{
if (Position > 0)
SellMarket(Position);
else
BuyMarket(-Position);
}
return;
}
if (est.DayOfWeek != EntryDay || est.Hour != EntryHour)
return;
// Avoid reopening right after the exit when entry and exit share the same moment.
if (est.DayOfWeek == ExitDay && est.Hour == ExitHour)
return;
if (IsLong)
BuyMarket(Volume);
else
SellMarket(Volume);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, DayOfWeek
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
EST_OFFSET = TimeSpan.FromHours(-5)
class btc_seasonality_strategy(Strategy):
"""
BTC Seasonality strategy.
Opens a long (IsLong) or short position at the first candle of EntryHour on EntryDay and closes it at the first candle of
ExitHour on ExitDay. Days and hours are in Eastern Standard Time (UTC-5).
"""
def __init__(self):
super(btc_seasonality_strategy, self).__init__()
self._entry_day = self.Param("EntryDay", DayOfWeek.Saturday).SetDisplay("Entry Day", "EST day of the entry", "Schedule")
self._exit_day = self.Param("ExitDay", DayOfWeek.Monday).SetDisplay("Exit Day", "EST day of the exit", "Schedule")
self._entry_hour = self.Param("EntryHour", 10).SetRange(0, 23).SetDisplay("Entry Hour", "EST hour of the entry", "Schedule")
self._exit_hour = self.Param("ExitHour", 10).SetRange(0, 23).SetDisplay("Exit Hour", "EST hour of the exit", "Schedule")
self._is_long = self.Param("IsLong", True).SetDisplay("Is Long", "Trade long when true, short otherwise", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(btc_seasonality_strategy, self).OnStarted2(time)
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
if not self.IsFormedAndOnlineAndAllowTrading():
return
est = candle.OpenTime.Add(EST_OFFSET)
is_exit_moment = est.DayOfWeek == self._exit_day.Value and est.Hour == self._exit_hour.Value
if self.Position != 0:
if is_exit_moment:
if self.Position > 0:
self.SellMarket(self.Position)
else:
self.BuyMarket(-self.Position)
return
if est.DayOfWeek != self._entry_day.Value or est.Hour != self._entry_hour.Value:
return
# Avoid reopening right after the exit when entry and exit share the same moment.
if is_exit_moment:
return
if self._is_long.Value:
self.BuyMarket(self.Volume)
else:
self.SellMarket(self.Volume)
def CreateClone(self):
return btc_seasonality_strategy()