Ver en GitHub

Roulette Game

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);
		}
	}
}