TDS Global戦略
この戦略は、Alexander ElderのTriple Screenコンセプトに基づくMetaTraderオリジナルの「TDSGlobal」エキスパートを再現します。日足ローソク足を評価し、MACD(12、23、9)の傾きと24期間のWilliams %Rフィルターを組み合わせます。システムはトレンドが上向きに転じ、%Rが売られすぎの状態を示しているときに買いを求め、トレンドが下向きに転じ、%Rが買われすぎを示しているときに売りを求めます。
有効なセットアップが検出されるたびに、戦略は前のセッションの高値または安値を超えてストップ注文を置きます。エントリーは、元の「16ポイント」オフセットロジックを反映して、価格に近すぎるエントリーを避けるために設定可能なバッファによって現在の市場から遠ざけられます。ポジションを取ると、戦略は保護ストップ、オプションのテイクプロフィット、および価格ステップでのトレーリングストップを管理します。
トレードロジック
- データ: デフォルトで日足ローソク足で動作します(設定可能)。
- トレンドフィルター: 最近の2つのMACD主線値を比較します。MACDの上昇はロングバイアスを意味し、MACDの下降はショートバイアスを意味します。
- オシレーターフィルター: 前のWilliams %R値を使用します。
WilliamsBuyLevel(デフォルト-75)以下ではロングセットアップを許可し、WilliamsSellLevel(デフォルト-25)以上ではショートセットアップを許可します。 - エントリー:
- ロング: 前の高値プラス1価格ステップを超えてbuy-stopを置きます。エントリーは市場との最小距離を保つために最後の終値より少なくとも
EntryBufferSteps価格ステップ上に引き上げられます。 - ショート: 前の安値マイナス1価格ステップ未満にsell-stopを置きます。注文は最大で最後の終値マイナス
EntryBufferStepsステップまで引き下げられます。
- ロング: 前の高値プラス1価格ステップを超えてbuy-stopを置きます。エントリーは市場との最小距離を保つために最後の終値より少なくとも
- リスク管理:
- 初期ストップは前のローソク足の反対側の極値に固定されます(ショートには高値、ロングには安値)。
- テイクプロフィット距離は
TakeProfitSteps価格ステップに等しくなります。デフォルト値(999)は非常に広いターゲットを使用したMQLバージョンに近い動作を保持します。 - トレーリングストップは
TrailingStopSteps> 0のときに有効になります。それだけのステップ数で終値に追随し、取引の方向にのみ締まります。
- 注文処理:
- エントリー価格または保護レベルを更新する必要がある場合、既存のストップ注文はキャンセルされ更新されます。
- 反対方向のトレンドシグナルは、MACDの方向と一致しなくなったペンディング注文を削除します。
- ポジションが開かれると、保存されたペンディングレベルはライブのストップ/テイク価格を初期化するために再利用されます。
- オプションの段階的配置: 元のEAは、同時ペンディング注文を避けるためにFXペア間で注文配置を段階的にしていました。
UseSymbolStaggerをtrueに設定すると、EURUSD、GBPUSD、USDCHF、USDJPYに同じ分ウィンドウが適用されます。
パラメーター
MacdFastLength、MacdSlowLength、MacdSignalLength– トレンド傾斜チェックに使用されるMACDの期間。WilliamsLength– Williams %Rのルックバック。WilliamsBuyLevel、WilliamsSellLevel– 売られすぎ/買われすぎのしきい値(負の値、それぞれ-100/-0に近い)。EntryBufferSteps– ストップエントリーを置く際の現在の市場からの最小オフセット(価格ステップ数)。TakeProfitSteps– 価格ステップでのターゲット距離(ハードターゲットを有効にするには小さい数を設定)。TrailingStopSteps– ステップ単位のトレーリングストップ距離; トレーリングを無効にするにはゼロに設定。UseSymbolStagger– シンボル固有の分ウィンドウを有効にします。CandleType– ローソク足の時間軸(デフォルトは日足)。
注意事項
- ロットサイズを制御するために戦略ボリュームを使用します。ボリュームが指定されていない場合はデフォルトで1になります。
- ペンディング注文とトレーリングエグジットは完成したローソク足で動作するため、ローソク足のクローズ間の約定は保存されたエントリー価格で近似されます。
- テイクプロフィットのデフォルト値は元のEAの動作に合わせるために大きくなっています。有限のターゲットが必要な場合は調整してください。
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>
/// Triple screen style daily breakout strategy using MACD slope and Williams %R.
/// Places stop orders beyond the prior day's extremes and manages trailing exits.
/// </summary>
public class TdsGlobalStrategy : Strategy
{
private readonly StrategyParam<int> _macdFastLength;
private readonly StrategyParam<int> _macdSlowLength;
private readonly StrategyParam<int> _macdSignalLength;
private readonly StrategyParam<int> _williamsLength;
private readonly StrategyParam<decimal> _williamsBuyLevel;
private readonly StrategyParam<decimal> _williamsSellLevel;
private readonly StrategyParam<int> _entryBufferSteps;
private readonly StrategyParam<decimal> _takeProfitSteps;
private readonly StrategyParam<decimal> _trailingStopSteps;
private readonly StrategyParam<bool> _useSymbolStagger;
private readonly StrategyParam<DataType> _candleType;
private decimal _priceStep;
private decimal? _macdPrev1;
private decimal? _macdPrev2;
private decimal? _williamsPrev1;
private decimal? _prevHigh;
private decimal? _prevLow;
private decimal? _prevClose;
private bool _hasPendingOrder;
private Sides? _pendingSide;
private decimal? _pendingEntryPrice;
private decimal? _pendingStopPrice;
private decimal? _pendingTakePrice;
private decimal? _entryPrice;
private decimal? _stopPrice;
private decimal? _takePrice;
private DateTimeOffset? _lastEntryTime;
/// <summary>
/// Fast EMA period used by MACD.
/// </summary>
public int MacdFastLength
{
get => _macdFastLength.Value;
set => _macdFastLength.Value = value;
}
/// <summary>
/// Slow EMA period used by MACD.
/// </summary>
public int MacdSlowLength
{
get => _macdSlowLength.Value;
set => _macdSlowLength.Value = value;
}
/// <summary>
/// Signal period for MACD.
/// </summary>
public int MacdSignalLength
{
get => _macdSignalLength.Value;
set => _macdSignalLength.Value = value;
}
/// <summary>
/// Williams %R lookback length.
/// </summary>
public int WilliamsLength
{
get => _williamsLength.Value;
set => _williamsLength.Value = value;
}
/// <summary>
/// Oversold threshold for Williams %R.
/// </summary>
public decimal WilliamsBuyLevel
{
get => _williamsBuyLevel.Value;
set => _williamsBuyLevel.Value = value;
}
/// <summary>
/// Overbought threshold for Williams %R.
/// </summary>
public decimal WilliamsSellLevel
{
get => _williamsSellLevel.Value;
set => _williamsSellLevel.Value = value;
}
/// <summary>
/// Minimum distance from market price when placing stop entries (in steps).
/// </summary>
public int EntryBufferSteps
{
get => _entryBufferSteps.Value;
set => _entryBufferSteps.Value = value;
}
/// <summary>
/// Take profit distance expressed in price steps.
/// </summary>
public decimal TakeProfitSteps
{
get => _takeProfitSteps.Value;
set => _takeProfitSteps.Value = value;
}
/// <summary>
/// Trailing stop distance expressed in price steps.
/// </summary>
public decimal TrailingStopSteps
{
get => _trailingStopSteps.Value;
set => _trailingStopSteps.Value = value;
}
/// <summary>
/// Enable symbol specific minute windows for order placement.
/// </summary>
public bool UseSymbolStagger
{
get => _useSymbolStagger.Value;
set => _useSymbolStagger.Value = value;
}
/// <summary>
/// Candle type used for calculations (defaults to daily candles).
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="TdsGlobalStrategy"/> class.
/// </summary>
public TdsGlobalStrategy()
{
_macdFastLength = Param(nameof(MacdFastLength), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "Fast EMA length", "MACD");
_macdSlowLength = Param(nameof(MacdSlowLength), 23)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "Slow EMA length", "MACD");
_macdSignalLength = Param(nameof(MacdSignalLength), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal", "Signal line length", "MACD");
_williamsLength = Param(nameof(WilliamsLength), 24)
.SetGreaterThanZero()
.SetDisplay("Williams Length", "%R lookback", "Filters");
_williamsBuyLevel = Param(nameof(WilliamsBuyLevel), 30m)
.SetDisplay("Williams Buy", "Oversold threshold", "Filters");
_williamsSellLevel = Param(nameof(WilliamsSellLevel), 70m)
.SetDisplay("Williams Sell", "Overbought threshold", "Filters");
_entryBufferSteps = Param(nameof(EntryBufferSteps), 16)
.SetGreaterThanZero()
.SetDisplay("Entry Buffer", "Minimum distance from market in steps", "Risk");
_takeProfitSteps = Param(nameof(TakeProfitSteps), 999m)
.SetDisplay("Take Profit Steps", "Target distance in price steps", "Risk");
_trailingStopSteps = Param(nameof(TrailingStopSteps), 10m)
.SetDisplay("Trailing Stop Steps", "Trailing stop distance in steps", "Risk");
_useSymbolStagger = Param(nameof(UseSymbolStagger), false)
.SetDisplay("Use Time Windows", "Apply symbol specific minute windows", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_priceStep = 0m;
_macdPrev1 = null;
_macdPrev2 = null;
_williamsPrev1 = null;
_prevHigh = null;
_prevLow = null;
_prevClose = null;
ResetPendingOrder();
ResetPositionState();
_lastEntryTime = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_priceStep = Security?.PriceStep ?? 1m;
if (_priceStep <= 0)
_priceStep = 1m;
var macd = new MACD
{
ShortMa = { Length = MacdFastLength },
LongMa = { Length = MacdSlowLength },
};
var williams = new RelativeStrengthIndex { Length = WilliamsLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(macd, williams, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal macdLine, decimal williams)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormed)
{
UpdateHistory(macdLine, williams, candle);
return;
}
ManageOpenPosition(candle);
if (Math.Abs(Position) > 0)
{
UpdateHistory(macdLine, williams, candle);
return;
}
if (_macdPrev1 is null || _macdPrev2 is null || _williamsPrev1 is null ||
_prevHigh is null || _prevLow is null || _prevClose is null)
{
UpdateHistory(macdLine, williams, candle);
return;
}
if (UseSymbolStagger && !IsWithinAllowedWindow(candle.CloseTime))
{
UpdateHistory(macdLine, williams, candle);
return;
}
var direction = _macdPrev1 > _macdPrev2 ? 1 : _macdPrev1 < _macdPrev2 ? -1 : 0;
var oversold = _williamsPrev1 <= WilliamsBuyLevel;
var overbought = _williamsPrev1 >= WilliamsSellLevel;
var volume = Volume;
if (volume <= 0)
volume = 1m;
var cooldownPassed = _lastEntryTime is null || candle.CloseTime - _lastEntryTime >= TimeSpan.FromHours(24);
if (direction > 0 && oversold && cooldownPassed)
{
PlaceBuyStop(volume, candle.CloseTime);
}
else if (direction < 0 && overbought && cooldownPassed)
{
PlaceSellStop(volume, candle.CloseTime);
}
else if (_hasPendingOrder)
{
if ((_pendingSide == Sides.Buy && direction < 0) ||
(_pendingSide == Sides.Sell && direction > 0))
{
ResetPendingOrder();
}
}
UpdateHistory(macdLine, williams, candle);
}
private void ManageOpenPosition(ICandleMessage candle)
{
var position = Position;
if (position > 0)
{
if (_entryPrice is null)
{
_entryPrice = _pendingEntryPrice ?? candle.ClosePrice;
_stopPrice = _pendingStopPrice;
_takePrice = _pendingTakePrice;
ResetPendingOrder();
}
if (TrailingStopSteps > 0)
{
var trailing = candle.ClosePrice - TrailingStopSteps * _priceStep;
if (_stopPrice is null || trailing > _stopPrice)
_stopPrice = trailing;
}
if (_stopPrice is not null && candle.LowPrice <= _stopPrice)
{
if (Position > 0) SellMarket(Math.Abs(Position)); else if (Position < 0) BuyMarket(Math.Abs(Position));
ResetPositionState();
ResetPendingOrder();
return;
}
if (_takePrice is not null && candle.HighPrice >= _takePrice)
{
if (Position > 0) SellMarket(Math.Abs(Position)); else if (Position < 0) BuyMarket(Math.Abs(Position));
ResetPositionState();
ResetPendingOrder();
}
}
else if (position < 0)
{
if (_entryPrice is null)
{
_entryPrice = _pendingEntryPrice ?? candle.ClosePrice;
_stopPrice = _pendingStopPrice;
_takePrice = _pendingTakePrice;
ResetPendingOrder();
}
if (TrailingStopSteps > 0)
{
var trailing = candle.ClosePrice + TrailingStopSteps * _priceStep;
if (_stopPrice is null || trailing < _stopPrice)
_stopPrice = trailing;
}
if (_stopPrice is not null && candle.HighPrice >= _stopPrice)
{
if (Position > 0) SellMarket(Math.Abs(Position)); else if (Position < 0) BuyMarket(Math.Abs(Position));
ResetPositionState();
ResetPendingOrder();
return;
}
if (_takePrice is not null && candle.LowPrice <= _takePrice)
{
if (Position > 0) SellMarket(Math.Abs(Position)); else if (Position < 0) BuyMarket(Math.Abs(Position));
ResetPositionState();
ResetPendingOrder();
}
}
else
{
ResetPositionState();
}
}
private void PlaceBuyStop(decimal volume, DateTimeOffset time)
{
if (_prevHigh is null || _prevLow is null || _prevClose is null)
return;
var entryPrice = Math.Max(_prevHigh.Value + _priceStep, _prevClose.Value + EntryBufferSteps * _priceStep);
var stopPrice = _prevLow.Value - _priceStep;
var takePrice = TakeProfitSteps > 0 ? entryPrice + TakeProfitSteps * _priceStep : (decimal?)null;
if (_hasPendingOrder && _pendingSide == Sides.Buy &&
_pendingEntryPrice == entryPrice &&
_pendingStopPrice == stopPrice &&
_pendingTakePrice == takePrice)
{
return;
}
BuyMarket(volume);
_lastEntryTime = time;
_pendingSide = Sides.Buy;
_pendingEntryPrice = entryPrice;
_pendingStopPrice = stopPrice;
_pendingTakePrice = takePrice;
_hasPendingOrder = true;
}
private void PlaceSellStop(decimal volume, DateTimeOffset time)
{
if (_prevHigh is null || _prevLow is null || _prevClose is null)
return;
var entryPrice = Math.Min(_prevLow.Value - _priceStep, _prevClose.Value - EntryBufferSteps * _priceStep);
var stopPrice = _prevHigh.Value + _priceStep;
var takePrice = TakeProfitSteps > 0 ? entryPrice - TakeProfitSteps * _priceStep : (decimal?)null;
if (_hasPendingOrder && _pendingSide == Sides.Sell &&
_pendingEntryPrice == entryPrice &&
_pendingStopPrice == stopPrice &&
_pendingTakePrice == takePrice)
{
return;
}
SellMarket(volume);
_lastEntryTime = time;
_pendingSide = Sides.Sell;
_pendingEntryPrice = entryPrice;
_pendingStopPrice = stopPrice;
_pendingTakePrice = takePrice;
_hasPendingOrder = true;
}
private void ResetPendingOrder()
{
_hasPendingOrder = false;
_pendingSide = null;
_pendingEntryPrice = null;
_pendingStopPrice = null;
_pendingTakePrice = null;
}
private void ResetPositionState()
{
_entryPrice = null;
_stopPrice = null;
_takePrice = null;
}
private void UpdateHistory(decimal macdLine, decimal williams, ICandleMessage candle)
{
if (_macdPrev1 is not null)
_macdPrev2 = _macdPrev1;
_macdPrev1 = macdLine;
_williamsPrev1 = williams;
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
_prevClose = candle.ClosePrice;
}
private bool IsWithinAllowedWindow(DateTimeOffset time)
{
if (!UseSymbolStagger)
return true;
var minute = time.Minute;
var code = Security?.Code?.ToUpperInvariant();
switch (code)
{
case "USDCHF":
return (minute >= 0 && minute <= 1) || (minute >= 8 && minute <= 9) ||
(minute >= 16 && minute <= 17) || (minute >= 24 && minute <= 25) ||
(minute >= 32 && minute <= 33) || (minute >= 40 && minute <= 41) ||
(minute >= 48 && minute <= 49);
case "GBPUSD":
return (minute >= 2 && minute <= 3) || (minute >= 10 && minute <= 11) ||
(minute >= 18 && minute <= 19) || (minute >= 26 && minute <= 27) ||
(minute >= 34 && minute <= 35) || (minute >= 42 && minute <= 43) ||
(minute >= 50 && minute <= 51);
case "USDJPY":
return (minute >= 4 && minute <= 5) || (minute >= 12 && minute <= 13) ||
(minute >= 20 && minute <= 21) || (minute >= 28 && minute <= 29) ||
(minute >= 36 && minute <= 37) || (minute >= 44 && minute <= 45) ||
(minute >= 52 && minute <= 53);
case "EURUSD":
return (minute >= 6 && minute <= 7) || (minute >= 14 && minute <= 15) ||
(minute >= 22 && minute <= 23) || (minute >= 30 && minute <= 31) ||
(minute >= 38 && minute <= 39) || (minute >= 46 && minute <= 47) ||
(minute >= 54 && minute <= 59);
default:
return true;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import MovingAverageConvergenceDivergence, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class tds_global_strategy(Strategy):
def __init__(self):
super(tds_global_strategy, self).__init__()
self._macd_fast_length = self.Param("MacdFastLength", 12)
self._macd_slow_length = self.Param("MacdSlowLength", 23)
self._macd_signal_length = self.Param("MacdSignalLength", 9)
self._williams_length = self.Param("WilliamsLength", 24)
self._williams_buy_level = self.Param("WilliamsBuyLevel", 30.0)
self._williams_sell_level = self.Param("WilliamsSellLevel", 70.0)
self._entry_buffer_steps = self.Param("EntryBufferSteps", 16)
self._take_profit_steps = self.Param("TakeProfitSteps", 999.0)
self._trailing_stop_steps = self.Param("TrailingStopSteps", 10.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._price_step = 1.0
self._macd_prev1 = None
self._macd_prev2 = None
self._williams_prev1 = None
self._prev_high = None
self._prev_low = None
self._prev_close = None
self._entry_price = None
self._stop_price = None
self._take_price = None
@property
def MacdFastLength(self):
return self._macd_fast_length.Value
@MacdFastLength.setter
def MacdFastLength(self, value):
self._macd_fast_length.Value = value
@property
def MacdSlowLength(self):
return self._macd_slow_length.Value
@MacdSlowLength.setter
def MacdSlowLength(self, value):
self._macd_slow_length.Value = value
@property
def MacdSignalLength(self):
return self._macd_signal_length.Value
@MacdSignalLength.setter
def MacdSignalLength(self, value):
self._macd_signal_length.Value = value
@property
def WilliamsLength(self):
return self._williams_length.Value
@WilliamsLength.setter
def WilliamsLength(self, value):
self._williams_length.Value = value
@property
def WilliamsBuyLevel(self):
return self._williams_buy_level.Value
@WilliamsBuyLevel.setter
def WilliamsBuyLevel(self, value):
self._williams_buy_level.Value = value
@property
def WilliamsSellLevel(self):
return self._williams_sell_level.Value
@WilliamsSellLevel.setter
def WilliamsSellLevel(self, value):
self._williams_sell_level.Value = value
@property
def EntryBufferSteps(self):
return self._entry_buffer_steps.Value
@EntryBufferSteps.setter
def EntryBufferSteps(self, value):
self._entry_buffer_steps.Value = value
@property
def TakeProfitSteps(self):
return self._take_profit_steps.Value
@TakeProfitSteps.setter
def TakeProfitSteps(self, value):
self._take_profit_steps.Value = value
@property
def TrailingStopSteps(self):
return self._trailing_stop_steps.Value
@TrailingStopSteps.setter
def TrailingStopSteps(self, value):
self._trailing_stop_steps.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(tds_global_strategy, self).OnStarted2(time)
self._price_step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self._price_step <= 0.0:
self._price_step = 1.0
self._macd_prev1 = None
self._macd_prev2 = None
self._williams_prev1 = None
self._prev_high = None
self._prev_low = None
self._prev_close = None
self._entry_price = None
self._stop_price = None
self._take_price = None
macd = MovingAverageConvergenceDivergence()
macd.ShortMa.Length = self.MacdFastLength
macd.LongMa.Length = self.MacdSlowLength
williams = RelativeStrengthIndex()
williams.Length = self.WilliamsLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(macd, williams, self.ProcessCandle).Start()
self.StartProtection(
Unit(2000.0, UnitTypes.Absolute),
Unit(1000.0, UnitTypes.Absolute))
def ProcessCandle(self, candle, macd_line, williams):
if candle.State != CandleStates.Finished:
return
macd_val = float(macd_line)
williams_val = float(williams)
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
self._manage_open_position(candle)
if abs(self.Position) > 0:
self._update_history(macd_val, williams_val, candle)
return
if self._macd_prev1 is None or self._macd_prev2 is None or \
self._williams_prev1 is None or self._prev_high is None or \
self._prev_low is None or self._prev_close is None:
self._update_history(macd_val, williams_val, candle)
return
direction = 1 if self._macd_prev1 > self._macd_prev2 else (-1 if self._macd_prev1 < self._macd_prev2 else 0)
oversold = self._williams_prev1 <= float(self.WilliamsBuyLevel)
overbought = self._williams_prev1 >= float(self.WilliamsSellLevel)
if direction > 0 and oversold:
self.BuyMarket()
entry = close
tp_steps = float(self.TakeProfitSteps)
self._entry_price = entry
self._stop_price = self._prev_low - self._price_step
self._take_price = entry + tp_steps * self._price_step if tp_steps > 0.0 else None
elif direction < 0 and overbought:
self.SellMarket()
entry = close
tp_steps = float(self.TakeProfitSteps)
self._entry_price = entry
self._stop_price = self._prev_high + self._price_step
self._take_price = entry - tp_steps * self._price_step if tp_steps > 0.0 else None
self._update_history(macd_val, williams_val, candle)
def _manage_open_position(self, candle):
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
if self.Position > 0:
if self._entry_price is None:
self._entry_price = close
trail_steps = float(self.TrailingStopSteps)
if trail_steps > 0.0:
trailing = close - trail_steps * self._price_step
if self._stop_price is None or trailing > self._stop_price:
self._stop_price = trailing
if self._stop_price is not None and low <= self._stop_price:
self.SellMarket()
self._reset_position()
return
if self._take_price is not None and high >= self._take_price:
self.SellMarket()
self._reset_position()
elif self.Position < 0:
if self._entry_price is None:
self._entry_price = close
trail_steps = float(self.TrailingStopSteps)
if trail_steps > 0.0:
trailing = close + trail_steps * self._price_step
if self._stop_price is None or trailing < self._stop_price:
self._stop_price = trailing
if self._stop_price is not None and high >= self._stop_price:
self.BuyMarket()
self._reset_position()
return
if self._take_price is not None and low <= self._take_price:
self.BuyMarket()
self._reset_position()
else:
self._reset_position()
def _update_history(self, macd_val, williams_val, candle):
if self._macd_prev1 is not None:
self._macd_prev2 = self._macd_prev1
self._macd_prev1 = macd_val
self._williams_prev1 = williams_val
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
self._prev_close = float(candle.ClosePrice)
def _reset_position(self):
self._entry_price = None
self._stop_price = None
self._take_price = None
def OnReseted(self):
super(tds_global_strategy, self).OnReseted()
self._price_step = 1.0
self._macd_prev1 = None
self._macd_prev2 = None
self._williams_prev1 = None
self._prev_high = None
self._prev_low = None
self._prev_close = None
self._reset_position()
def CreateClone(self):
return tds_global_strategy()