This strategy replicates the Volume Weighted MA Digit System. It builds two volume weighted moving averages (VWMA) based on candle highs and lows. The price crossing these bands provides trading signals.
How It Works
Indicators
VWMA High: VWMA applied to candle highs.
VWMA Low: VWMA applied to candle lows.
Signals
Long Entry: Close price crosses above VWMA High.
Short Entry: Close price crosses below VWMA Low.
Opposite cross closes open positions.
Risk Management
Uses built‑in StartProtection with configurable stop loss and take profit (points).
Parameters
Name
Description
Default
VwmaPeriod
VWMA calculation length
12
CandleType
Candle timeframe used for calculation
4h
StopLoss
Stop loss in points
1000
TakeProfit
Take profit in points
2000
Notes
Only closed candles are processed.
Strategy uses high level API features such as SubscribeCandles, Bind and standard indicators.
Original MQL strategy: Exp_Volume_Weighted_MA_Digit_System.mq5.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on Volume Weighted MA slope turning points.
/// Opens long when VWMA slope turns upward, short when it turns downward.
/// </summary>
public class VolumeWeightedMaDigitSystemStrategy : Strategy
{
private readonly StrategyParam<int> _vwmaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevVwma;
private decimal? _prevSlope;
public int VwmaPeriod
{
get => _vwmaPeriod.Value;
set => _vwmaPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public VolumeWeightedMaDigitSystemStrategy()
{
_vwmaPeriod = Param(nameof(VwmaPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("VWMA Period", "Length of the VWMA indicator", "Parameters")
.SetOptimize(5, 30, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe for analysis", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevVwma = null;
_prevSlope = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevVwma = null;
_prevSlope = null;
var vwma = new VolumeWeightedMovingAverage { Length = VwmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(vwma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, vwma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal vwmaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevVwma is decimal prev)
{
var slope = vwmaValue - prev;
if (_prevSlope is decimal prevSlope)
{
var turnedUp = prevSlope <= 0 && slope > 0;
var turnedDown = prevSlope >= 0 && slope < 0;
if (turnedUp && Position <= 0)
BuyMarket();
else if (turnedDown && Position >= 0)
SellMarket();
}
_prevSlope = slope;
}
_prevVwma = vwmaValue;
}
}
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 VolumeWeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class volume_weighted_ma_digit_system_strategy(Strategy):
def __init__(self):
super(volume_weighted_ma_digit_system_strategy, self).__init__()
self._vwma_period = self.Param("VwmaPeriod", 12) \
.SetDisplay("VWMA Period", "Length of the VWMA indicator", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe for analysis", "Parameters")
self._prev_vwma = None
self._prev_slope = None
@property
def vwma_period(self):
return self._vwma_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(volume_weighted_ma_digit_system_strategy, self).OnReseted()
self._prev_vwma = None
self._prev_slope = None
def OnStarted2(self, time):
super(volume_weighted_ma_digit_system_strategy, self).OnStarted2(time)
self._prev_vwma = None
self._prev_slope = None
vwma = VolumeWeightedMovingAverage()
vwma.Length = self.vwma_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(vwma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, vwma)
self.DrawOwnTrades(area)
def process_candle(self, candle, vwma_value):
if candle.State != CandleStates.Finished:
return
vwma_value = float(vwma_value)
if self._prev_vwma is not None:
slope = vwma_value - self._prev_vwma
if self._prev_slope is not None:
turned_up = self._prev_slope <= 0 and slope > 0
turned_down = self._prev_slope >= 0 and slope < 0
if turned_up and self.Position <= 0:
self.BuyMarket()
elif turned_down and self.Position >= 0:
self.SellMarket()
self._prev_slope = slope
self._prev_vwma = vwma_value
def CreateClone(self):
return volume_weighted_ma_digit_system_strategy()