The Roulette Game strategy recreates the casino-like expert advisor from MetaTrader inside StockSharp. It treats every finished candle as a new spin of the wheel, chooses a random direction, and scales its order size after losses using a Martingale-style progression. The implementation keeps track of a virtual bankroll and limits exposure through configurable caps.
Every round starts by flattening any existing position, flipping a virtual coin to represent red or black, and sending a market order in the selected direction. When the next candle closes, the strategy checks whether the close moved in favor of the bet. Wins reset the stake to the base volume, while losses multiply the stake up to a defined ceiling. A maximum losing streak guard forces a reset before the exposure becomes extreme. Optional cooldown candles can be inserted between rounds to slow the pace of betting.
This conversion focuses on the gambling-inspired money management showcased by the original expert instead of indicator signals. It demonstrates how to orchestrate time-based rounds, maintain internal state, and interact with StockSharp's high-level API through candle subscriptions.
Details
Entry Criteria: No technical filter. Direction is selected randomly at the end of a finished candle.
Long/Short: Both directions, picked randomly each round.
Exit Criteria: Position closes on the next finished candle, evaluating whether the price closed above or below the entry.
Stops: No traditional stops. Risk is managed with stake caps and streak limits.
Default Values:
BaseVolume = 1m
LossMultiplier = 2m
MaxMultiplier = 16m
RoundCooldown = 1
MaxLosingStreak = 5
CandleType = TimeSpan.FromMinutes(1)
Filters:
Category: Money Management
Direction: Both
Indicators: None
Stops: No
Complexity: Beginner
Timeframe: Short-term
Seasonality: No
Neural Networks: No
Divergence: No
Risk Level: High
Notes
Market orders are sized according to the multiplier-adjusted stake and rounded to the instrument's volume step.
Wins reset the stake to the base volume; losses scale it by the multiplier until the maximum multiplier or losing streak limit is reached.
Cooldown bars prevent immediate re-entry and make it possible to synchronize with slower data feeds.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Roulette Game strategy: random-like entries based on candle direction with SMA filter.
/// Buys when candle is bullish and close above SMA. Sells when bearish and below SMA.
/// </summary>
public class RouletteGameStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smaPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
public RouletteGameStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_smaPeriod = Param(nameof(SmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = SmaPeriod };
decimal? prevClose = null;
decimal? prevSma = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, (candle, smaVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var isBullish = close > candle.OpenPrice;
if (prevClose.HasValue && prevSma.HasValue)
{
var crossUp = prevClose.Value <= prevSma.Value && close > smaVal;
var crossDown = prevClose.Value >= prevSma.Value && close < smaVal;
if (isBullish && crossUp && Position <= 0)
BuyMarket();
else if (!isBullish && crossDown && Position >= 0)
SellMarket();
}
prevClose = close;
prevSma = smaVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class roulette_game_strategy(Strategy):
def __init__(self):
super(roulette_game_strategy, self).__init__()
self._sma_period = self.Param("SmaPeriod", 20).SetGreaterThanZero().SetDisplay("SMA Period", "SMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Candle 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(roulette_game_strategy, self).OnReseted()
self._prev_close = 0
self._prev_sma = 0
self._has_prev = False
def OnStarted2(self, time):
super(roulette_game_strategy, self).OnStarted2(time)
self._prev_close = 0
self._prev_sma = 0
self._has_prev = False
sma = SimpleMovingAverage()
sma.Length = self._sma_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(sma, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def OnProcess(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
is_bullish = close > candle.OpenPrice
if self._has_prev:
cross_up = self._prev_close <= self._prev_sma and close > sma_val
cross_down = self._prev_close >= self._prev_sma and close < sma_val
if is_bullish and cross_up and self.Position <= 0:
self.BuyMarket()
elif not is_bullish and cross_down and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_sma = sma_val
self._has_prev = True
def CreateClone(self):
return roulette_game_strategy()