This strategy is a C# port of the original MetaTrader script "GO". It calculates a custom oscillator from moving averages of open, high, low and close prices and uses it to determine market direction.
Strategy Logic
Four moving averages are built using the same period and method for the open, high, low and close series.
The GO value is computed on every finished candle:
When the GO value becomes positive, all short positions are closed and a new long position is opened.
When the GO value becomes negative, all long positions are closed and a new short position is opened.
Only one trade per bar is allowed. New entries are taken until the total number of open positions reaches Max Positions.
Parameters
Risk % – percentage of account equity used to calculate trade volume.
Max Positions – maximum number of open positions allowed in one direction.
MA Type – type of moving average (SMA, EMA, DEMA, TEMA, WMA, VWMA).
MA Period – period for all moving averages.
Candle Type – candle series used for indicator calculations.
Notes
The implementation uses the high-level API of StockSharp. It subscribes to candles, binds indicators and draws them on the chart. The trade volume is adjusted according to the specified risk percentage and the security volume limits.
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()