GO 策略
该策略是原始 MetaTrader 脚本 "GO" 的 C# 移植版本。它基于开盘价、最高价、最低价和收盘价的移动平均线计算自定义振荡器,并用其确定市场方向。
策略逻辑
对 Open、High、Low、Close 四个价格序列使用相同周期和方法构建移动平均线。
在每根完成的 K 线上计算 GO 值:
GO = ((MA_close - MA_open) + (MA_high - MA_open) + (MA_low - MA_open) + (MA_close - MA_low) + (MA_close - MA_high)) * Volume当 GO 值为正时,平掉所有空头仓位并开多单。
当 GO 值为负时,平掉所有多头仓位并开空单。
每根 K 线上只允许一次交易,直到开仓数量达到 Max Positions 参数。
参数
- Risk % – 用于计算交易量的账户资金百分比。
- Max Positions – 同方向允许的最大持仓数量。
- MA Type – 移动平均线类型(SMA、EMA、DEMA、TEMA、WMA、VWMA)。
- MA Period – 所有移动平均线的周期。
- Candle Type – 用于计算的 K 线类型。
备注
该实现使用 StockSharp 的高级 API。策略订阅 K 线、绑定指标并在图表上绘制它们。交易量根据设置的风险百分比和品种的交易量限制自动调整。
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()