在 GitHub 上查看
Virtual TradePad Signal 策略
本策略将 MetaTrader 中的 VirtualTradePad 指标面板移植到 StockSharp。系统会监控 12 个趋势、通道与动量指标,
只有在达到设定数量的同向信号时才进场,从而把原始面板的情绪矩阵转化为自动化交易逻辑。
工作原理
- 数据:在选定的蜡烛类型(默认 15 分钟)上交易单一品种。
- 指标:
- 快速/慢速简单移动平均的金叉死叉。
- MACD 主线与信号线交叉。
- 随机指标 %K 穿越 20/80 区域。
- RSI 穿越 30/70。
- CCI 穿越 -100/+100。
- Williams %R 穿越 -80/-20。
- 价格重新回到布林带内部。
- 价格重新回到 SMA 百分比通道内部。
- 比尔·威廉姆斯鳄鱼线(颚、牙、唇)排列方向。
- Kaufman 自适应均线的斜率(上升/下降)。
- Awesome Oscillator 穿越零轴。
- Ichimoku Tenkan 与 Kijun 的交叉。
- 每个指标都会产生 +1(做多)、-1(做空)或 0(中性)的投票。当多头(或空头)投票数量达到
MinimumConfirmations 参数并且多于反方向时,策略将开仓。
CloseOnOpposite 选项会在反向投票达到阈值时平仓。
- 风险控制:可选的止盈/止损,单位为品种的价格步长。
参数
FastMaLength, SlowMaLength —— 均线周期。
MacdFastLength, MacdSlowLength, MacdSignalLength —— MACD 设置。
StochasticLength, StochasticDLength, StochasticSlowing —— 随机指标设置。
RsiLength, CciLength, WilliamsLength —— 震荡指标周期。
BollingerLength, BollingerDeviation —— 布林带参数。
EnvelopeLength, EnvelopeDeviation —— SMA 百分比通道宽度。
AlligatorJawLength, AlligatorTeethLength, AlligatorLipsLength —— 鳄鱼线 SMMA 周期。
AmaLength, AmaFastPeriod, AmaSlowPeriod —— Kaufman AMA 设置。
IchimokuTenkanLength, IchimokuKijunLength, IchimokuSenkouLength —— Ichimoku 参数。
AoShortPeriod, AoLongPeriod —— Awesome Oscillator 周期。
MinimumConfirmations —— 进场所需同向信号数量。
AllowLong, AllowShort —— 是否允许做多/做空。
CloseOnOpposite —— 反向信号达到阈值时是否平仓。
TakeProfitPips, StopLossPips —— 以价格步长表示的止盈/止损(0 表示禁用)。
CandleType —— 使用的蜡烛类型或时间框。
交易流程
- 每根蜡烛收盘时计算所有指标。
- 统计多头与空头票数。
- 当票数满足阈值并且领先于反方向时开仓。
- 如果启用
CloseOnOpposite,在反向票数满足阈值时平仓。
- 根据需要应用止盈与止损。
该策略适用于喜欢 VirtualTradePad 情绪面板、同时希望在 StockSharp 中获得自动化实现的交易者。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class VirtualTradePadSignalStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private decimal? _prevCci;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public VirtualTradePadSignalStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 20).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = null;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal cciVal)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevCci = cciVal; return; }
if (_prevCci == null) { _prevCci = cciVal; return; }
if (_prevCci.Value < 0m && cciVal >= 0m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevCci.Value > 0m && cciVal <= 0m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevCci = cciVal;
}
}
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
from StockSharp.Algo.Indicators import CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class virtual_trade_pad_signal_strategy(Strategy):
"""CCI crossing zero line for buy/sell signals."""
def __init__(self):
super(virtual_trade_pad_signal_strategy, self).__init__()
self._cci_period = self.Param("CciPeriod", 20).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(virtual_trade_pad_signal_strategy, self).OnReseted()
self._prev_cci = None
def OnStarted2(self, time):
super(virtual_trade_pad_signal_strategy, self).OnStarted2(time)
self._prev_cci = None
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(cci, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle, cci_val):
if candle.State != CandleStates.Finished:
return
cv = float(cci_val)
if self._prev_cci is not None:
if self._prev_cci < 0 and cv >= 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_cci > 0 and cv <= 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_cci = cv
def CreateClone(self):
return virtual_trade_pad_signal_strategy()