Эта стратегия представляет собой порт оригинального скрипта MetaTrader "GO" на C#. Она рассчитывает специальный осциллятор из скользящих средних цены открытия, максимума, минимума и закрытия и использует его для определения направления рынка.
Логика стратегии
Строятся четыре скользящих средних с одинаковым периодом и методом по рядам Open, High, Low и Close.
На каждой завершённой свече вычисляется значение GO:
Когда значение GO становится положительным, все короткие позиции закрываются и открывается новая длинная позиция.
Когда значение GO становится отрицательным, все длинные позиции закрываются и открывается новая короткая позиция.
За одну свечу допускается только одна сделка. Входы выполняются, пока общее число открытых позиций не достигнет параметра Max Positions.
Параметры
Risk % – процент капитала, используемый для расчёта объёма сделки.
Max Positions – максимальное число открытых позиций в одном направлении.
MA Type – тип скользящей средней (SMA, EMA, DEMA, TEMA, WMA, VWMA).
MA Period – период всех скользящих средних.
Candle Type – серия свечей, используемая для расчётов.
Примечания
В реализации используется высокоуровневый API StockSharp. Стратегия подписывается на свечи, связывает индикаторы и выводит их на график. Объём сделки корректируется в соответствии с указанным риском и ограничениями по объёму инструмента.
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()