GO リスク管理戦略
この戦略は、オリジナルのMetaTraderスクリプト「GO」をC#に移植したものです。始値・高値・安値・終値の移動平均からカスタムオシレーターを計算し、市場の方向性を判断します。
戦略ロジック
Open、High、Low、Closeの各シリーズに対して、同じ期間と手法で4本の移動平均を構築します。
完成した各ローソク足でGO値を計算します:
GO = ((MA_close - MA_open) + (MA_high - MA_open) + (MA_low - MA_open) + (MA_close - MA_low) + (MA_close - MA_high)) * VolumeGO値が正になると、すべてのショートポジションを決済し、新しいロングポジションを建てます。
GO値が負になると、すべてのロングポジションを決済し、新しいショートポジションを建てます。
1バーにつき1トレードのみ許可されます。オープンポジションの合計数がMax Positionsに達するまで新規エントリーを行います。
パラメーター
- Risk % – 取引量を計算するために使用するアカウント資産の割合。
- Max Positions – 一方向で許可されるオープンポジションの最大数。
- MA Type – 移動平均の種類(SMA、EMA、DEMA、TEMA、WMA、VWMA)。
- MA Period – すべての移動平均の期間。
- Candle Type – インジケーター計算に使用するローソク足シリーズ。
注記
この実装はStockSharpの高レベルAPIを使用しています。ローソク足を購読し、インジケーターをバインドしてチャートに描画します。取引量は指定されたリスク割合と銘柄の出来高制限に応じて調整されます。
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;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// GO strategy based on moving averages of open, high, low and close prices.
/// Closes opposite positions when the GO value changes sign.
/// Opens new trades in the direction of the GO value.
/// </summary>
public class GoRiskManagedStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _openMa;
private SimpleMovingAverage _closeMa;
private decimal? _prevGo;
/// <summary>
/// Moving average period.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Candle type used for indicators and trading logic.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes <see cref="GoRiskManagedStrategy"/>.
/// </summary>
public GoRiskManagedStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 10)
.SetDisplay("MA Period", "Moving average period", "Indicator")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevGo = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_openMa = new SimpleMovingAverage { Length = MaPeriod };
_closeMa = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_closeMa, (candle, close) =>
{
if (candle.State != CandleStates.Finished)
return;
var openResult = _openMa.Process(candle.OpenPrice, candle.CloseTime, true);
if (!_openMa.IsFormed || !_closeMa.IsFormed)
return;
var open = openResult.ToDecimal();
var go = close - open;
if (_prevGo is not decimal prevGo)
{
_prevGo = go;
return;
}
if (prevGo <= 0m && go > 0m && Position <= 0)
BuyMarket();
else if (prevGo >= 0m && go < 0m && Position >= 0)
SellMarket();
_prevGo = go;
})
.Start();
StartProtection(
new Unit(2000m, UnitTypes.Absolute),
new Unit(1000m, UnitTypes.Absolute));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class go_risk_managed_strategy(Strategy):
"""
GO strategy: moving averages of open vs close prices.
Buys when GO (close_ma - open_ma) crosses above zero.
Sells when GO crosses below zero. Uses StartProtection for SL/TP.
"""
def __init__(self):
super(go_risk_managed_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 10) \
.SetDisplay("MA Period", "Moving average period", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._open_ma = None
self._prev_go = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(go_risk_managed_strategy, self).OnReseted()
self._prev_go = None
def OnStarted2(self, time):
super(go_risk_managed_strategy, self).OnStarted2(time)
self._open_ma = SimpleMovingAverage()
self._open_ma.Length = self._ma_period.Value
close_ma = SimpleMovingAverage()
close_ma.Length = self._ma_period.Value
self.Indicators.Add(self._open_ma)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(close_ma, self._process_candle).Start()
self.StartProtection(
Unit(2000, UnitTypes.Absolute),
Unit(1000, UnitTypes.Absolute))
def _process_candle(self, candle, close_val):
if candle.State != CandleStates.Finished:
return
open_result = process_float(self._open_ma, candle.OpenPrice, candle.OpenTime, True)
if not self._open_ma.IsFormed:
return
open_v = float(open_result)
close_v = float(close_val)
go = close_v - open_v
if self._prev_go is None:
self._prev_go = go
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_go = go
return
if self._prev_go <= 0 and go > 0 and self.Position <= 0:
self.BuyMarket()
elif self._prev_go >= 0 and go < 0 and self.Position >= 0:
self.SellMarket()
self._prev_go = go
def CreateClone(self):
return go_risk_managed_strategy()