ホーム
/
戦略のサンプル
GitHub で見る
Labouchere EA Strategy
This strategy combines a Stochastic Oscillator crossover with a Labouchere money management sequence. The Stochastic indicator generates signals when %K crosses %D. The Labouchere system adjusts trade volume after each closed position: losses append a new element equal to the sum of the first and last numbers in the sequence, while profits remove these elements.
Trades are taken only on finished candles. The sequence can optionally restart when all numbers are removed. A time filter allows trading within a specific intraday window, and opposite signals can close existing positions. Fixed stop-loss and take-profit levels (in price steps) are supported.
Details
Entry Criteria :
Long : %K crosses above %D.
Short : %K crosses below %D.
Long/Short : Both sides.
Exit Criteria :
Optional opposite signal exit.
Fixed stop-loss and take-profit (if set).
Stops : Yes.
Money Management : Labouchere sequence.
Default Values :
LotSequence = "0.01,0.02,0.01,0.02,0.01,0.01,0.01,0.01"
NewRecycle = true
StopLoss = 40
TakeProfit = 50
IsReversed = false
UseOppositeExit = false
UseWorkTime = false
StartTime = 00:00
StopTime = 24:00
KPeriod = 10
DPeriod = 190
Filters :
Category: Mixed
Direction: Both
Indicators: Stochastic Oscillator
Stops: Yes
Complexity: Intermediate
Timeframe: Intraday
Seasonality: No
Neural networks: No
Divergence: No
Risk Level: Medium
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;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Labouchere betting system strategy using Stochastic oscillator for signals.
/// Adjusts position sizing based on the Labouchere sequence.
/// </summary>
public class LabouchereEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _kPeriod;
private readonly StrategyParam<int> _dPeriod;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<decimal> _takeProfitPct;
private decimal? _prevK;
private decimal? _prevD;
private decimal _entryPrice;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int KPeriod { get => _kPeriod.Value; set => _kPeriod.Value = value; }
public int DPeriod { get => _dPeriod.Value; set => _dPeriod.Value = value; }
public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
public LabouchereEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles used", "General");
_kPeriod = Param(nameof(KPeriod), 10)
.SetDisplay("K Period", "Stochastic %K period", "Indicator")
.SetGreaterThanZero();
_dPeriod = Param(nameof(DPeriod), 3)
.SetDisplay("D Period", "Stochastic %D period", "Indicator")
.SetGreaterThanZero();
_stopLossPct = Param(nameof(StopLossPct), 1m)
.SetDisplay("Stop Loss %", "Stop loss percent", "Risk")
.SetGreaterThanZero();
_takeProfitPct = Param(nameof(TakeProfitPct), 1.5m)
.SetDisplay("Take Profit %", "Take profit percent", "Risk")
.SetGreaterThanZero();
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var stoch = new StochasticOscillator
{
K = { Length = KPeriod },
D = { Length = DPeriod }
};
StartProtection(
takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
stopLoss: new Unit(StopLossPct, UnitTypes.Percent));
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(stoch, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue stochValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!stochValue.IsFinal || !stochValue.IsFormed)
return;
var stoch = (IStochasticOscillatorValue)stochValue;
if (stoch.K is not decimal k || stoch.D is not decimal d)
return;
var signal = 0;
if (_prevK.HasValue && _prevD.HasValue)
{
if (_prevK <= _prevD && k > d)
signal = 1;
else if (_prevK >= _prevD && k < d)
signal = -1;
}
_prevK = k;
_prevD = d;
if (signal == 0)
return;
if (signal > 0 && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = candle.ClosePrice;
}
else if (signal < 0 && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = candle.ClosePrice;
}
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevK = null;
_prevD = null;
_entryPrice = 0m;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
class labouchere_ea_strategy(Strategy):
"""
Labouchere strategy using Stochastic K/D crossover for entry signals.
Uses StartProtection for percentage-based SL/TP.
"""
def __init__(self):
super(labouchere_ea_strategy, self).__init__()
self._k_period = self.Param("KPeriod", 10) \
.SetDisplay("K Period", "Stochastic %K period", "Indicator")
self._d_period = self.Param("DPeriod", 3) \
.SetDisplay("D Period", "Stochastic %D period", "Indicator")
self._stop_loss_pct = self.Param("StopLossPct", 1.0) \
.SetDisplay("Stop Loss %", "Stop loss percent", "Risk")
self._take_profit_pct = self.Param("TakeProfitPct", 1.5) \
.SetDisplay("Take Profit %", "Take profit percent", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles used", "General")
self._prev_k = None
self._prev_d = None
self._entry_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(labouchere_ea_strategy, self).OnReseted()
self._prev_k = None
self._prev_d = None
self._entry_price = 0.0
def OnStarted2(self, time):
super(labouchere_ea_strategy, self).OnStarted2(time)
stoch = StochasticOscillator()
stoch.K.Length = self._k_period.Value
stoch.D.Length = self._d_period.Value
self.StartProtection(
Unit(self._take_profit_pct.Value, UnitTypes.Percent),
Unit(self._stop_loss_pct.Value, UnitTypes.Percent))
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(stoch, self._process_candle).Start()
def _process_candle(self, candle, stoch_value):
if candle.State != CandleStates.Finished:
return
if not stoch_value.IsFormed:
return
k = stoch_value.K
d = stoch_value.D
if k is None or d is None:
return
k = float(k)
d = float(d)
signal = 0
if self._prev_k is not None and self._prev_d is not None:
if self._prev_k <= self._prev_d and k > d:
signal = 1
elif self._prev_k >= self._prev_d and k < d:
signal = -1
self._prev_k = k
self._prev_d = d
if signal == 0:
return
if signal > 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = float(candle.ClosePrice)
elif signal < 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = float(candle.ClosePrice)
def CreateClone(self):
return labouchere_ea_strategy()