Millenium Code戦略
Millenium Code戦略は、1日に最大1回の取引を開く位置取引システムです。方向は、最近の高値と安値でフィルタリングされた移動平均クロスオーバーによって決定されます。取引はユーザーが定義した時間に置かれ、時間、ストップロス、テイクプロフィット、または最大期間によってクローズされます。
取引ロジック
- 指定された開始時間に、戦略は現在の曜日に取引が許可されているかどうかを確認します。
- 速い単純移動平均と遅い単純移動平均が比較されます。速いMAが遅いMAを上回り、価格がブレイクアウトを確認した場合、ロングポジションが開かれます。逆の条件でショートポジションが開かれます。
- 1日に1回の取引のみ許可されます。次の取引日まで、後続のシグナルは無視されます。
- 以下の場合にポジションがクローズされます:
- ストップロスまたはテイクプロフィットのレベルに達した場合。
- 設定されたクローズ時間が来た場合。
- 最大取引期間を超えた場合。
パラメーター
- Candle Type – 入力ローソク足の時間軸。
- Fast MA – 速い移動平均の期間。
- Slow MA – 遅い移動平均の期間。
- HighLow Bars – 最近の高値と安値を検索するために使用するローソク足の数。
- Reverse – 買い/売りシグナルを反転します。
- Stop Loss – 価格ステップ単位のストップロスまでの距離。
- Take Profit – 価格ステップ単位のテイクプロフィットまでの距離。
- Open Hour/Minute – エントリーを探し始める時間(-1で無効)。
- Close Hour/Minute – ポジションをクローズする時間(-1で無効)。
- Duration – 最大取引期間(時間単位、0で無効)。
- Sunday ... Friday – 各曜日の取引を有効にします。
注意事項
この戦略は高レベルAPIの機能のみを使用し、インジケーターの履歴に直接アクセスすることを避けています。教育的な例として意図されており、投資アドバイスではありません。
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>
/// Millenium Code positional strategy.
/// Uses fast/slow MA crossover with high/low channel filter.
/// </summary>
public class MilleniumCodeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _highLowBars;
private readonly StrategyParam<bool> _reverseSignal;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<decimal> _takeProfitPct;
private Highest _highest;
private Lowest _lowest;
private decimal _prevFast;
private decimal _prevSlow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public int HighLowBars { get => _highLowBars.Value; set => _highLowBars.Value = value; }
public bool ReverseSignal { get => _reverseSignal.Value; set => _reverseSignal.Value = value; }
public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
public MilleniumCodeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_fastLength = Param(nameof(FastLength), 10)
.SetDisplay("Fast MA", "Fast moving average length", "Indicators");
_slowLength = Param(nameof(SlowLength), 30)
.SetDisplay("Slow MA", "Slow moving average length", "Indicators");
_highLowBars = Param(nameof(HighLowBars), 10)
.SetDisplay("HighLow Bars", "Bars count for high/low search", "Indicators");
_reverseSignal = Param(nameof(ReverseSignal), true)
.SetDisplay("Reverse", "Reverse buy/sell logic", "General");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_highest = default;
_lowest = default;
_prevFast = 0m;
_prevSlow = 0m;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastLength };
var slow = new ExponentialMovingAverage { Length = SlowLength };
_highest = new Highest { Length = HighLowBars };
_lowest = new Lowest { Length = HighLowBars };
Indicators.Add(_highest);
Indicators.Add(_lowest);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, (candle, fastVal, slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
var highResult = _highest.Process(candle);
var lowResult = _lowest.Process(candle);
if (!highResult.IsFormed || !lowResult.IsFormed)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var high = highResult.ToDecimal();
var low = lowResult.ToDecimal();
if (_prevFast == 0 || _prevSlow == 0)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var crossUp = _prevFast < _prevSlow && fastVal > slowVal;
var crossDown = _prevFast > _prevSlow && fastVal < slowVal;
var dir = 0;
if (crossUp) dir = ReverseSignal ? -1 : 1;
else if (crossDown) dir = ReverseSignal ? 1 : -1;
if (dir == 1 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (dir == -1 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}).Start();
StartProtection(
takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
}
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
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage, Highest, Lowest, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class millenium_code_strategy(Strategy):
def __init__(self):
super(millenium_code_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._fast_length = self.Param("FastLength", 10) \
.SetDisplay("Fast MA", "Fast moving average length", "Indicators")
self._slow_length = self.Param("SlowLength", 30) \
.SetDisplay("Slow MA", "Slow moving average length", "Indicators")
self._high_low_bars = self.Param("HighLowBars", 10) \
.SetDisplay("HighLow Bars", "Bars count for high/low search", "Indicators")
self._reverse_signal = self.Param("ReverseSignal", True) \
.SetDisplay("Reverse", "Reverse buy/sell logic", "General")
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._take_profit_pct = self.Param("TakeProfitPct", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._highest = None
self._lowest = None
self._prev_fast = 0.0
self._prev_slow = 0.0
@property
def candle_type(self):
return self._candle_type.Value
@property
def fast_length(self):
return self._fast_length.Value
@property
def slow_length(self):
return self._slow_length.Value
@property
def high_low_bars(self):
return self._high_low_bars.Value
@property
def reverse_signal(self):
return self._reverse_signal.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def take_profit_pct(self):
return self._take_profit_pct.Value
def OnReseted(self):
super(millenium_code_strategy, self).OnReseted()
self._highest = None
self._lowest = None
self._prev_fast = 0.0
self._prev_slow = 0.0
def OnStarted2(self, time):
super(millenium_code_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self.fast_length
slow = ExponentialMovingAverage()
slow.Length = self.slow_length
self._highest = Highest()
self._highest.Length = self.high_low_bars
self._lowest = Lowest()
self._lowest.Length = self.high_low_bars
self.Indicators.Add(self._highest)
self.Indicators.Add(self._lowest)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self.on_candle).Start()
self.StartProtection(
takeProfit=Unit(self.take_profit_pct, UnitTypes.Percent),
stopLoss=Unit(self.stop_loss_pct, UnitTypes.Percent),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def on_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_val)
slow_val = float(slow_val)
cv_h = CandleIndicatorValue(self._highest, candle)
high_result = self._highest.Process(cv_h)
cv_l = CandleIndicatorValue(self._lowest, candle)
low_result = self._lowest.Process(cv_l)
if not high_result.IsFormed or not low_result.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast == 0.0 or self._prev_slow == 0.0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
cross_up = self._prev_fast < self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast > self._prev_slow and fast_val < slow_val
direction = 0
if cross_up:
direction = -1 if self.reverse_signal else 1
elif cross_down:
direction = 1 if self.reverse_signal else -1
if direction == 1 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif direction == -1 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return millenium_code_strategy()