IU 上位時間軸 MA クロス戦略
IU Higher Timeframe MA Cross戦略は、ユーザーが選択した時間軸で計算された高速移動平均が、別の時間軸の低速移動平均を上抜けまたは下抜けたときに取引します。強気クロスでロングポジション、弱気クロスでショートポジションを開きます。ストップロスは前のローソク足の極値に設定され、テイクプロフィットは設定可能なリスク・リワード比を使用します。
詳細
- データ: 指定した時間軸のローソク足。
- エントリー条件:
- ロング: MA1がMA2を上抜け。
- ショート: MA1がMA2を下抜け。
- エグジット条件: ストップロスまたはテイクプロフィット到達。
- ストップ: 前のローソク足の高値/安値に
RiskToReward乗数を適用。 - デフォルト値:
Ma1CandleType= 60mMa1Length= 20Ma1Type= MovingAverageTypeEnum.ExponentialMa2CandleType= 60mMa2Length= 50Ma2Type= MovingAverageTypeEnum.ExponentialRiskToReward= 2
- フィルター:
- カテゴリ: トレンド
- 方向: ロング & ショート
- インジケーター: 移動平均
- 複雑さ: 低
- リスクレベル: 中
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
using StockSharp.Algo;
namespace StockSharp.Samples.Strategies;
public class IUHigherTimeframeMACrossStrategy : Strategy
{
private readonly StrategyParam<decimal> _riskToReward;
private readonly StrategyParam<DataType> _ma1CandleType;
private readonly StrategyParam<int> _ma1Length;
private readonly StrategyParam<MovingAverageTypes> _ma1Type;
private readonly StrategyParam<DataType> _ma2CandleType;
private readonly StrategyParam<int> _ma2Length;
private readonly StrategyParam<MovingAverageTypes> _ma2Type;
private decimal? _ma1;
private decimal? _ma2;
private decimal? _prevMa1;
private decimal? _prevMa2;
private decimal? _entryPrice;
private decimal? _stopPrice;
private decimal? _takePrice;
private decimal? _prevLow;
private decimal? _prevHigh;
private ICandleMessage _lastMa1Candle;
private DecimalLengthIndicator _ma1Indicator;
private DecimalLengthIndicator _ma2Indicator;
public IUHigherTimeframeMACrossStrategy()
{
_riskToReward = Param(nameof(RiskToReward), 2m)
.SetGreaterThanZero()
.SetDisplay("RTR", "Risk to reward ratio", "Protection")
.SetOptimize(1m, 5m, 0.5m);
_ma1CandleType = Param(nameof(Ma1CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("MA1 Timeframe", "Timeframe for first MA", "Moving Averages");
_ma1Length = Param(nameof(Ma1Length), 20)
.SetGreaterThanZero()
.SetDisplay("MA1 Length", "Period for first MA", "Moving Averages")
.SetOptimize(5, 100, 5);
_ma1Type = Param(nameof(Ma1Type), MovingAverageTypes.Exponential)
.SetDisplay("MA1 Type", "Type of first MA", "Moving Averages");
_ma2CandleType = Param(nameof(Ma2CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("MA2 Timeframe", "Timeframe for second MA", "Moving Averages");
_ma2Length = Param(nameof(Ma2Length), 50)
.SetGreaterThanZero()
.SetDisplay("MA2 Length", "Period for second MA", "Moving Averages")
.SetOptimize(10, 200, 5);
_ma2Type = Param(nameof(Ma2Type), MovingAverageTypes.Exponential)
.SetDisplay("MA2 Type", "Type of second MA", "Moving Averages");
}
public decimal RiskToReward { get => _riskToReward.Value; set => _riskToReward.Value = value; }
public DataType Ma1CandleType { get => _ma1CandleType.Value; set => _ma1CandleType.Value = value; }
public int Ma1Length { get => _ma1Length.Value; set => _ma1Length.Value = value; }
public MovingAverageTypes Ma1Type { get => _ma1Type.Value; set => _ma1Type.Value = value; }
public DataType Ma2CandleType { get => _ma2CandleType.Value; set => _ma2CandleType.Value = value; }
public int Ma2Length { get => _ma2Length.Value; set => _ma2Length.Value = value; }
public MovingAverageTypes Ma2Type { get => _ma2Type.Value; set => _ma2Type.Value = value; }
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, Ma1CandleType), (Security, Ma2CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ma1 = null;
_ma2 = null;
_prevMa1 = null;
_prevMa2 = null;
_entryPrice = null;
_stopPrice = null;
_takePrice = null;
_prevLow = null;
_prevHigh = null;
_lastMa1Candle = null;
_ma1Indicator = null;
_ma2Indicator = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ma1Indicator = CreateMa(Ma1Type, Ma1Length);
_ma2Indicator = CreateMa(Ma2Type, Ma2Length);
var ma1Sub = SubscribeCandles(Ma1CandleType);
ma1Sub.Bind(_ma1Indicator, ProcessMa1).Start();
var ma2Sub = SubscribeCandles(Ma2CandleType);
ma2Sub.Bind(_ma2Indicator, ProcessMa2).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, ma1Sub);
DrawIndicator(area, _ma1Indicator);
DrawIndicator(area, _ma2Indicator);
DrawOwnTrades(area);
}
}
private void ProcessMa1(ICandleMessage candle, decimal value)
{
if (candle.State != CandleStates.Finished)
return;
if (_lastMa1Candle != null)
{
_prevLow = _lastMa1Candle.LowPrice;
_prevHigh = _lastMa1Candle.HighPrice;
}
_lastMa1Candle = candle;
_prevMa1 = _ma1;
_ma1 = value;
if (Position > 0)
{
if (_stopPrice.HasValue && candle.LowPrice <= _stopPrice)
CloseLong();
else if (_takePrice.HasValue && candle.HighPrice >= _takePrice)
CloseLong();
}
else if (Position < 0)
{
if (_stopPrice.HasValue && candle.HighPrice >= _stopPrice)
CloseShort();
else if (_takePrice.HasValue && candle.LowPrice <= _takePrice)
CloseShort();
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevMa1.HasValue && _prevMa2.HasValue && _ma1.HasValue && _ma2.HasValue && Position == 0)
{
var crossUp = _prevMa1 < _prevMa2 && _ma1 > _ma2;
var crossDown = _prevMa1 > _prevMa2 && _ma1 < _ma2;
if (crossUp)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
var sl = _prevLow ?? candle.LowPrice;
_stopPrice = sl;
_takePrice = (_entryPrice - sl) * RiskToReward + _entryPrice;
}
else if (crossDown)
{
SellMarket();
_entryPrice = candle.ClosePrice;
var sl = _prevHigh ?? candle.HighPrice;
_stopPrice = sl;
_takePrice = _entryPrice - (sl - _entryPrice) * RiskToReward;
}
}
}
private void ProcessMa2(ICandleMessage candle, decimal value)
{
if (candle.State != CandleStates.Finished)
return;
_prevMa2 = _ma2;
_ma2 = value;
}
private void CloseLong()
{
SellMarket(Position);
ResetProtection();
}
private void CloseShort()
{
BuyMarket(Math.Abs(Position));
ResetProtection();
}
private void ResetProtection()
{
_entryPrice = null;
_stopPrice = null;
_takePrice = null;
}
private static DecimalLengthIndicator CreateMa(MovingAverageTypes type, int length)
{
return type switch
{
MovingAverageTypes.Simple => new SMA { Length = length },
MovingAverageTypes.Exponential => new EMA { Length = length },
MovingAverageTypes.Smoothed => new SmoothedMovingAverage { Length = length },
MovingAverageTypes.Weighted => new WeightedMovingAverage { Length = length },
MovingAverageTypes.VolumeWeighted => new VolumeWeightedMovingAverage { Length = length },
_ => new SMA { Length = length },
};
}
public enum MovingAverageTypes
{
Simple,
Exponential,
Smoothed,
Weighted,
VolumeWeighted
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage as SMA, ExponentialMovingAverage as EMA, SmoothedMovingAverage, WeightedMovingAverage, VolumeWeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class iu_higher_timeframe_ma_cross_strategy(Strategy):
def __init__(self):
super(iu_higher_timeframe_ma_cross_strategy, self).__init__()
self._risk_to_reward = self.Param("RiskToReward", 2.0) \
.SetDisplay("RTR", "Risk to reward ratio", "Protection")
self._ma1_candle_type = self.Param("Ma1CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60))) \
.SetDisplay("MA1 Timeframe", "Timeframe for first MA", "Moving Averages")
self._ma1_length = self.Param("Ma1Length", 20) \
.SetDisplay("MA1 Length", "Period for first MA", "Moving Averages")
self._ma1_type = self.Param("Ma1Type", 1) \
.SetDisplay("MA1 Type", "Type of first MA (0=SMA,1=EMA,2=Smoothed,3=Weighted,4=VWMA)", "Moving Averages")
self._ma2_candle_type = self.Param("Ma2CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60))) \
.SetDisplay("MA2 Timeframe", "Timeframe for second MA", "Moving Averages")
self._ma2_length = self.Param("Ma2Length", 50) \
.SetDisplay("MA2 Length", "Period for second MA", "Moving Averages")
self._ma2_type = self.Param("Ma2Type", 1) \
.SetDisplay("MA2 Type", "Type of second MA (0=SMA,1=EMA,2=Smoothed,3=Weighted,4=VWMA)", "Moving Averages")
self._ma1 = None
self._ma2 = None
self._prev_ma1 = None
self._prev_ma2 = None
self._entry_price = None
self._stop_price = None
self._take_price = None
self._prev_low = None
self._prev_high = None
self._last_ma1_candle = None
@property
def risk_to_reward(self):
return self._risk_to_reward.Value
@property
def ma1_candle_type(self):
return self._ma1_candle_type.Value
@property
def ma1_length(self):
return self._ma1_length.Value
@property
def ma2_candle_type(self):
return self._ma2_candle_type.Value
@property
def ma2_length(self):
return self._ma2_length.Value
def _create_ma(self, ma_type, length):
t = int(ma_type)
if t == 0:
ma = SMA()
elif t == 1:
ma = EMA()
elif t == 2:
ma = SmoothedMovingAverage()
elif t == 3:
ma = WeightedMovingAverage()
elif t == 4:
ma = VolumeWeightedMovingAverage()
else:
ma = SMA()
ma.Length = length
return ma
def OnReseted(self):
super(iu_higher_timeframe_ma_cross_strategy, self).OnReseted()
self._ma1 = None
self._ma2 = None
self._prev_ma1 = None
self._prev_ma2 = None
self._entry_price = None
self._stop_price = None
self._take_price = None
self._prev_low = None
self._prev_high = None
self._last_ma1_candle = None
def OnStarted2(self, time):
super(iu_higher_timeframe_ma_cross_strategy, self).OnStarted2(time)
ma1_ind = self._create_ma(self._ma1_type.Value, self.ma1_length)
ma2_ind = self._create_ma(self._ma2_type.Value, self.ma2_length)
ma1_sub = self.SubscribeCandles(self.ma1_candle_type)
ma1_sub.Bind(ma1_ind, self._process_ma1).Start()
ma2_sub = self.SubscribeCandles(self.ma2_candle_type)
ma2_sub.Bind(ma2_ind, self._process_ma2).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, ma1_sub)
self.DrawIndicator(area, ma1_ind)
self.DrawIndicator(area, ma2_ind)
self.DrawOwnTrades(area)
def _process_ma1(self, candle, value):
if candle.State != CandleStates.Finished:
return
if self._last_ma1_candle is not None:
self._prev_low = float(self._last_ma1_candle.LowPrice)
self._prev_high = float(self._last_ma1_candle.HighPrice)
self._last_ma1_candle = candle
self._prev_ma1 = self._ma1
self._ma1 = float(value)
pos = self.Position
if pos > 0:
if self._stop_price is not None and float(candle.LowPrice) <= self._stop_price:
self.SellMarket(pos)
self._reset_protection()
elif self._take_price is not None and float(candle.HighPrice) >= self._take_price:
self.SellMarket(pos)
self._reset_protection()
elif pos < 0:
if self._stop_price is not None and float(candle.HighPrice) >= self._stop_price:
self.BuyMarket(abs(pos))
self._reset_protection()
elif self._take_price is not None and float(candle.LowPrice) <= self._take_price:
self.BuyMarket(abs(pos))
self._reset_protection()
if self._prev_ma1 is not None and self._prev_ma2 is not None and self._ma1 is not None and self._ma2 is not None and self.Position == 0:
cross_up = self._prev_ma1 < self._prev_ma2 and self._ma1 > self._ma2
cross_down = self._prev_ma1 > self._prev_ma2 and self._ma1 < self._ma2
if cross_up:
self.BuyMarket()
self._entry_price = float(candle.ClosePrice)
sl = self._prev_low if self._prev_low is not None else float(candle.LowPrice)
self._stop_price = sl
self._take_price = (self._entry_price - sl) * float(self.risk_to_reward) + self._entry_price
elif cross_down:
self.SellMarket()
self._entry_price = float(candle.ClosePrice)
sl = self._prev_high if self._prev_high is not None else float(candle.HighPrice)
self._stop_price = sl
self._take_price = self._entry_price - (sl - self._entry_price) * float(self.risk_to_reward)
def _process_ma2(self, candle, value):
if candle.State != CandleStates.Finished:
return
self._prev_ma2 = self._ma2
self._ma2 = float(value)
def _reset_protection(self):
self._entry_price = None
self._stop_price = None
self._take_price = None
def CreateClone(self):
return iu_higher_timeframe_ma_cross_strategy()