Lucky Code is a short-term breakout scalper converted from the original MetaTrader "Lucky_code" expert advisor. The strategy watches the spread extremes and reacts when the best ask jumps above or the best bid falls below the previous quote by a configurable distance. All trades are closed aggressively: profits are taken immediately once price ticks favorably, while losses are cut when an adverse excursion breaches a protective limit.
Data and execution
Market data: requires a steady stream of Level 1 quotes to read the latest best bid and ask values.
Order types: uses market orders for every entry and exit to mirror the tick-based execution of the MQL version.
Position mode: supports both netting and hedging accounts. Multiple fills accumulate into a single net position that is managed as a block.
Parameters
Shift points – minimum number of points (pips) between consecutive quotes that unlocks a new entry. Higher values reduce trade frequency and noise sensitivity.
Limit points – maximum adverse distance allowed before positions are force-closed. The value is converted into price units with the instrument tick size.
Trading logic
Initialization
Converts point-based parameters into real price offsets using the security tick size.
Subscribes to Level 1 data and resets the internal buffers for the last seen bid and ask.
Entry rules
When the best ask advances by at least the configured shift above the previous ask, the strategy opens a short position (matching the original EA behavior that sells after upward spikes).
When the best bid drops by at least the same shift under the previous bid, the strategy opens a long position to capture the rebound.
Volume sizing
Starts from the strategy Volume property.
If the portfolio value is available, the size is increased to round(Equity / 10,000, 1) lots, emulating the MetaTrader margin-based sizing.
Exit rules
Long exposure is closed immediately once the bid exceeds the average entry price or the ask moves down by the configured loss limit.
Short exposure is closed once the ask falls below the entry price or the bid rises above it by the loss limit.
Implementation notes
The strategy reacts on every quote update, so consider throttling noisy feeds or increasing the shift parameter in production environments.
Because market orders are used for both opening and closing trades, ensure sufficient liquidity to avoid slippage spikes during fast quote jumps.
Additional portfolio-level risk controls (daily stop, maximum drawdown, etc.) are recommended when running the strategy live.
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;
using StockSharp.Algo;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Momentum strategy that opens trades when candle price jumps reach a configurable distance and manages exits with profit and drawdown filters.
/// </summary>
public class LuckyCodeStrategy : Strategy
{
private readonly StrategyParam<int> _shiftPoints;
private readonly StrategyParam<int> _limitPoints;
private decimal? _previousClose;
private decimal _shiftThreshold;
private decimal _limitThreshold;
private decimal _entryPrice;
private bool _thresholdsReady;
private int _holdBars;
/// <summary>
/// Minimum price movement in points required before opening a new trade.
/// </summary>
public int ShiftPoints
{
get => _shiftPoints.Value;
set => _shiftPoints.Value = value;
}
/// <summary>
/// Maximum adverse excursion in points tolerated before forcing an exit.
/// </summary>
public int LimitPoints
{
get => _limitPoints.Value;
set => _limitPoints.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public LuckyCodeStrategy()
{
_shiftPoints = Param(nameof(ShiftPoints), 3)
.SetGreaterThanZero()
.SetDisplay("Shift points", "Minimum price jump required to trigger entries", "Trading")
.SetOptimize(1, 20, 1);
_limitPoints = Param(nameof(LimitPoints), 18)
.SetGreaterThanZero()
.SetDisplay("Limit points", "Maximum number of points allowed against the position", "Risk management")
.SetOptimize(5, 100, 5);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousClose = null;
_shiftThreshold = 0m;
_limitThreshold = 0m;
_entryPrice = 0m;
_thresholdsReady = false;
_holdBars = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Subscribe to candles and process each finished candle.
var tf = TimeSpan.FromMinutes(5).TimeFrame();
SubscribeCandles(tf)
.Bind(ProcessCandle)
.Start();
}
private void EnsureThresholds(decimal price)
{
if (_thresholdsReady)
return;
if (price <= 0m)
return;
// Use percentage of price. ShiftPoints=3 means 3% shift, LimitPoints=18 means 18% limit.
_shiftThreshold = price * ShiftPoints * 0.01m;
_limitThreshold = price * LimitPoints * 0.01m;
_thresholdsReady = true;
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
EnsureThresholds(close);
if (!_thresholdsReady)
return;
// Count hold bars for position management.
if (Position != 0)
_holdBars++;
if (_previousClose is decimal prevClose)
{
var delta = close - prevClose;
// Only enter if flat.
if (Position == 0)
{
// Price dropped sharply -> buy on expected rebound.
if (-delta >= _shiftThreshold)
{
BuyMarket();
_entryPrice = close;
_holdBars = 0;
LogInfo($"Buy triggered by fast price drop. Price={close:0.#####}");
}
// Price rose sharply -> sell on expected reversal.
else if (delta >= _shiftThreshold)
{
SellMarket();
_entryPrice = close;
_holdBars = 0;
LogInfo($"Sell triggered by fast price rise. Price={close:0.#####}");
}
}
}
_previousClose = close;
TryClosePosition(close);
}
private void TryClosePosition(decimal currentPrice)
{
if (Position == 0)
return;
var avgPrice = _entryPrice;
if (avgPrice <= 0m)
return;
// Minimum hold of 3 bars before checking exit.
if (_holdBars < 3)
return;
// Use half of shift threshold as profit target.
var profitTarget = _shiftThreshold * 0.5m;
if (Position > 0)
{
// Close long on profit target or drawdown limit.
if (currentPrice - avgPrice >= profitTarget)
{
SellMarket();
_holdBars = 0;
LogInfo($"Closed long on profit. Price={currentPrice:0.#####}");
}
else if (_limitThreshold > 0m && avgPrice - currentPrice >= _limitThreshold)
{
SellMarket();
_holdBars = 0;
LogInfo($"Closed long on drawdown limit. Price={currentPrice:0.#####}");
}
}
else if (Position < 0)
{
// Close short on profit target or drawdown limit.
if (avgPrice - currentPrice >= profitTarget)
{
BuyMarket();
_holdBars = 0;
LogInfo($"Closed short on profit. Price={currentPrice:0.#####}");
}
else if (_limitThreshold > 0m && currentPrice - avgPrice >= _limitThreshold)
{
BuyMarket();
_holdBars = 0;
LogInfo($"Closed short on drawdown limit. Price={currentPrice:0.#####}");
}
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class lucky_code_strategy(Strategy):
"""Momentum strategy that opens trades when candle price jumps reach a configurable distance
and manages exits with profit and drawdown filters."""
def __init__(self):
super(lucky_code_strategy, self).__init__()
self._shift_points = self.Param("ShiftPoints", 3) \
.SetGreaterThanZero() \
.SetDisplay("Shift points", "Minimum price jump required to trigger entries", "Trading") \
.SetOptimize(1, 20, 1)
self._limit_points = self.Param("LimitPoints", 18) \
.SetGreaterThanZero() \
.SetDisplay("Limit points", "Maximum number of points allowed against the position", "Risk management") \
.SetOptimize(5, 100, 5)
self._previous_close = None
self._shift_threshold = 0.0
self._limit_threshold = 0.0
self._entry_price = 0.0
self._thresholds_ready = False
self._hold_bars = 0
@property
def ShiftPoints(self):
return self._shift_points.Value
@ShiftPoints.setter
def ShiftPoints(self, value):
self._shift_points.Value = value
@property
def LimitPoints(self):
return self._limit_points.Value
@LimitPoints.setter
def LimitPoints(self, value):
self._limit_points.Value = value
def OnReseted(self):
super(lucky_code_strategy, self).OnReseted()
self._previous_close = None
self._shift_threshold = 0.0
self._limit_threshold = 0.0
self._entry_price = 0.0
self._thresholds_ready = False
self._hold_bars = 0
def OnStarted2(self, time):
super(lucky_code_strategy, self).OnStarted2(time)
tf = DataType.TimeFrame(TimeSpan.FromMinutes(5))
subscription = self.SubscribeCandles(tf)
subscription.Bind(self._process_candle).Start()
def _ensure_thresholds(self, price):
if self._thresholds_ready:
return
if price <= 0.0:
return
# Use percentage of price. ShiftPoints=3 means 3% shift, LimitPoints=18 means 18% limit.
self._shift_threshold = price * self.ShiftPoints * 0.01
self._limit_threshold = price * self.LimitPoints * 0.01
self._thresholds_ready = True
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
self._ensure_thresholds(close)
if not self._thresholds_ready:
return
# Count hold bars for position management.
if self.Position != 0:
self._hold_bars += 1
if self._previous_close is not None:
prev_close = self._previous_close
delta = close - prev_close
# Only enter if flat.
if self.Position == 0:
# Price dropped sharply -> buy on expected rebound.
if (-delta) >= self._shift_threshold:
self.BuyMarket()
self._entry_price = close
self._hold_bars = 0
self.LogInfo("Buy triggered by fast price drop. Price=" + str(close))
# Price rose sharply -> sell on expected reversal.
elif delta >= self._shift_threshold:
self.SellMarket()
self._entry_price = close
self._hold_bars = 0
self.LogInfo("Sell triggered by fast price rise. Price=" + str(close))
self._previous_close = close
self._try_close_position(close)
def _try_close_position(self, current_price):
if self.Position == 0:
return
avg_price = self._entry_price
if avg_price <= 0.0:
return
# Minimum hold of 3 bars before checking exit.
if self._hold_bars < 3:
return
# Use half of shift threshold as profit target.
profit_target = self._shift_threshold * 0.5
if self.Position > 0:
# Close long on profit target or drawdown limit.
if current_price - avg_price >= profit_target:
self.SellMarket()
self._hold_bars = 0
self.LogInfo("Closed long on profit. Price=" + str(current_price))
elif self._limit_threshold > 0.0 and avg_price - current_price >= self._limit_threshold:
self.SellMarket()
self._hold_bars = 0
self.LogInfo("Closed long on drawdown limit. Price=" + str(current_price))
elif self.Position < 0:
# Close short on profit target or drawdown limit.
if avg_price - current_price >= profit_target:
self.BuyMarket()
self._hold_bars = 0
self.LogInfo("Closed short on profit. Price=" + str(current_price))
elif self._limit_threshold > 0.0 and current_price - avg_price >= self._limit_threshold:
self.BuyMarket()
self._hold_bars = 0
self.LogInfo("Closed short on drawdown limit. Price=" + str(current_price))
def CreateClone(self):
return lucky_code_strategy()