時間
タイミングユーティリティを示す戦略。高値が始値を指定ティック数上回る状態が指定期間続くと買いを入れます。
詳細
- エントリー条件: 高値から始値を引いた値が、指定秒数の間しきい値を上回り続けるとき。
- ロング/ショート: ロングのみ。
- エグジット条件: 条件が成立しなくなったとき。
- ストップ: なし。
- デフォルト値:
TicksFromOpen= 0SecondsCondition= 20ResetOnNewBar= trueCandleType= TimeSpan.FromMinutes(1)
- フィルター:
- カテゴリ: ブレイクアウト
- 方向: ロングのみ
- インジケーター: 価格
- ストップ: なし
- 複雑さ: 基本
- 時間軸: イントラデイ (1m)
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Timed intrabar high-above-open strategy.
/// </summary>
public class TimeStrategy : Strategy
{
private readonly StrategyParam<int> _ticksFromOpen;
private readonly StrategyParam<int> _secondsCondition;
private readonly StrategyParam<bool> _resetOnNewBar;
private readonly StrategyParam<DataType> _candleType;
private DateTime? _barStart;
private decimal _barOpen;
private decimal _barHigh;
private DateTime? _conditionSince;
public int TicksFromOpen { get => _ticksFromOpen.Value; set => _ticksFromOpen.Value = value; }
public int SecondsCondition { get => _secondsCondition.Value; set => _secondsCondition.Value = value; }
public bool ResetOnNewBar { get => _resetOnNewBar.Value; set => _resetOnNewBar.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TimeStrategy()
{
_ticksFromOpen = Param(nameof(TicksFromOpen), 0).SetNotNegative();
_secondsCondition = Param(nameof(SecondsCondition), 20).SetNotNegative();
_resetOnNewBar = Param(nameof(ResetOnNewBar), true);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame());
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, DataType.Level1)];
protected override void OnReseted()
{
base.OnReseted();
_barStart = null;
_barOpen = 0m;
_barHigh = 0m;
_conditionSince = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var quotes = new Subscription(DataType.Level1, Security);
// The archive carries bid/ask updates without LastTradePrice.
quotes.MarketData.BuildField = Level1Fields.BestAskPrice;
SubscribeLevel1(quotes).Bind(ProcessLevel1).Start();
}
private void ProcessLevel1(Level1ChangeMessage message)
{
var price =
message.TryGetDecimal(Level1Fields.LastTradePrice) ??
message.TryGetDecimal(Level1Fields.BestAskPrice) ??
message.TryGetDecimal(Level1Fields.BestBidPrice);
if (price is not decimal currentPrice || currentPrice <= 0m)
return;
var timeFrame = CandleType.Arg is TimeSpan tf && tf > TimeSpan.Zero
? tf
: TimeSpan.FromMinutes(1);
var currentBarStart = Align(message.ServerTime, timeFrame);
if (_barStart != currentBarStart)
{
_barStart = currentBarStart;
_barOpen = currentPrice;
_barHigh = currentPrice;
if (ResetOnNewBar)
_conditionSince = null;
}
else
_barHigh = Math.Max(_barHigh, currentPrice);
var point = Security?.PriceStep ?? 0m;
if (point <= 0m)
point = 0.0001m;
var condition = IsPriceConditionMet(_barOpen, _barHigh, point, TicksFromOpen);
if (!condition)
{
_conditionSince = null;
if (Position > 0m)
SellMarket(Math.Abs(Position));
return;
}
_conditionSince ??= message.ServerTime;
if (Position == 0m &&
message.ServerTime - _conditionSince.Value >= TimeSpan.FromSeconds(SecondsCondition))
BuyMarket();
}
internal static bool IsPriceConditionMet(
decimal open,
decimal high,
decimal priceStep,
int ticksFromOpen)
=> high - open > ticksFromOpen * priceStep;
private static DateTime Align(DateTime time, TimeSpan frame)
{
var ticks = time.TimeOfDay.Ticks / frame.Ticks * frame.Ticks;
return time.Date + TimeSpan.FromTicks(ticks);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, Level1Fields
from StockSharp.Algo.Strategies import Strategy
from StockSharp.BusinessEntities import Subscription
class time_strategy(Strategy):
def __init__(self):
super(time_strategy, self).__init__()
self._ticks_from_open = self.Param("TicksFromOpen", 0).SetNotNegative()
self._seconds_condition = self.Param("SecondsCondition", 20).SetNotNegative()
self._reset_on_new_bar = self.Param("ResetOnNewBar", True)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1)))
self._bar_start = None
self._bar_open = Decimal.Zero
self._bar_high = Decimal.Zero
self._condition_since = None
def GetWorkingSecurities(self):
return [(self.Security, DataType.Level1)]
def OnReseted(self):
super(time_strategy, self).OnReseted()
self._bar_start = None
self._bar_open = Decimal.Zero
self._bar_high = Decimal.Zero
self._condition_since = None
def OnStarted2(self, time):
super(time_strategy, self).OnStarted2(time)
quotes = Subscription(DataType.Level1, self.Security)
# Quote-only Level1 messages do not contain LastTradePrice.
quotes.MarketData.BuildField = Level1Fields.BestAskPrice
self.SubscribeLevel1(quotes).Bind(self._process_level1).Start()
def _process_level1(self, message):
price = message.Changes[Level1Fields.LastTradePrice] if message.Changes.ContainsKey(Level1Fields.LastTradePrice) else None
if price is None:
price = message.Changes[Level1Fields.BestAskPrice] if message.Changes.ContainsKey(Level1Fields.BestAskPrice) else None
if price is None:
price = message.Changes[Level1Fields.BestBidPrice] if message.Changes.ContainsKey(Level1Fields.BestBidPrice) else None
if price is None or price <= 0:
return
arg = self._candle_type.Value.Arg
frame = arg if isinstance(arg, TimeSpan) and arg > TimeSpan.Zero else TimeSpan.FromMinutes(1)
current_bar_start = self._align(message.ServerTime, frame)
if self._bar_start != current_bar_start:
self._bar_start = current_bar_start
self._bar_open = price
self._bar_high = price
if bool(self._reset_on_new_bar.Value):
self._condition_since = None
else:
self._bar_high = max(self._bar_high, price)
point = self.Security.PriceStep if self.Security is not None and self.Security.PriceStep is not None else Decimal.Zero
if point <= 0:
point = Decimal(0.0001)
condition = self.is_price_condition_met(
self._bar_open, self._bar_high, point, int(self._ticks_from_open.Value))
if not condition:
self._condition_since = None
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
return
if self._condition_since is None:
self._condition_since = message.ServerTime
if self.Position == 0 and (message.ServerTime - self._condition_since).TotalSeconds >= int(self._seconds_condition.Value):
self.BuyMarket()
@staticmethod
def is_price_condition_met(open_price, high, price_step, ticks_from_open):
return high - open_price > Decimal(ticks_from_open) * price_step
@staticmethod
def _align(time, frame):
ticks = (time.TimeOfDay.Ticks // frame.Ticks) * frame.Ticks
return time.Date.AddTicks(ticks)
def CreateClone(self):
return time_strategy()