True Sort 趋势策略
该策略复刻了 MetaTrader 中著名的 “True Sort” 模板:要求五条指数移动平均线严格排序。当当前和前一根已完成 K 线都呈现相同的多头或空头顺序,同时平均趋向指数(ADX)超过阈值以确认趋势强度时,策略顺势开仓。风控部分提供可选的绝对价差止损、止盈以及只有在价格足够向有利方向移动后才会启动的跟踪止损。
工作流程
- 在所选 K 线级别上计算五条 EMA(默认周期分别为 10、20、50、100、200)。
- 计算可配置周期的 ADX(默认 24),并要求其超过阈值(默认 20)以过滤弱趋势。
- 仅在 K 线收盘后分析指标,所有未完成的 K 线信号都会被忽略,避免过早下单。
- 做多条件(当前和上一根收盘 K 线均需满足):
EMA_fast > EMA_2 > EMA_3 > EMA_4 > EMA_slow,即多头排列。ADX > 阈值,确认趋势力度。
- 做空条件与上面完全相反,所有不等号方向互换。
- 当 EMA 排序被破坏、保护性价差被触及,或跟踪止损回吐既定利润时,仓位将被平掉。
双重排序验证能有效筛除噪声,使策略仅参与方向明确的行情。
交易规则
- 入场
- 多头:ADX 高于阈值,且五条 EMA 在当前和前一根已完成 K 线中都呈递减排序。若持有空头头寸,会先行平仓,再按
Volume设置的数量开多。 - 空头:ADX 高于阈值,且五条 EMA 在两根连续 K 线上都呈递增排序。若持有多头,会先行平仓后开空。
- 多头:ADX 高于阈值,且五条 EMA 在当前和前一根已完成 K 线中都呈递减排序。若持有空头头寸,会先行平仓,再按
- 出场
- 一旦 EMA 排列被破坏,即刻平仓。
- 可选风控措施:
- 在入场价下方(多头)或上方(空头)设置固定距离的止损。
- 在入场价外侧设置固定距离的止盈。
- 跟踪止损:只有在价格先运行
TrailingStopDistance + TrailingStepDistance后才激活,随后以TrailingStopDistance的距离跟随价格。
- 若出现手动平仓或外部成交,内部状态也会被重置。
参数
| 参数 | 说明 | 默认值 |
|---|---|---|
CandleType |
用于计算的 K 线数据类型。 | 1 小时 |
FastEmaLength |
最快 EMA 的周期。 | 10 |
SecondEmaLength |
第二条 EMA 的周期。 | 20 |
ThirdEmaLength |
第三条 EMA 的周期。 | 50 |
FourthEmaLength |
第四条 EMA 的周期。 | 100 |
SlowEmaLength |
最慢 EMA 的周期。 | 200 |
AdxPeriod |
ADX 指标的计算周期。 | 24 |
AdxThreshold |
允许交易的最小 ADX 值。 | 20 |
StopLossDistance |
绝对价格止损距离(0 表示关闭)。 | 0.005 |
TakeProfitDistance |
绝对价格止盈距离(0 表示关闭)。 | 0.015 |
TrailingStopDistance |
跟踪止损距离。 | 0.0005 |
TrailingStepDistance |
跟踪止损激活或移动前所需的额外价差。 | 0.0001 |
所有距离都以价格单位表示。对于 4/5 位小数报价的外汇品种,0.005 大约等于 50 个点。请根据交易品种的最小跳动调整这些数值。
使用建议
- 适用于外汇、指数、商品等趋势性资产。对于较长周期可适当增加 EMA 周期;用于短线时则可缩短周期。
- 两根 K 线的确认能够显著降低假突破,但也会导致信号略微滞后,可通过优化 EMA 周期和 ADX 阈值来平衡。
- 当
TrailingStepDistance = 0时,跟踪止损会在价格刚好运行TrailingStopDistance后立即启动,与原始 EA 的行为一致。 - 策略使用市价单(
BuyMarket、SellMarket)执行,仓位规模由Volume属性控制,可结合资金管理模块进一步扩展。 - 如需限制交易时段,可叠加会话过滤或更高周期的趋势判定。
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>
/// Trend-following strategy that requires five exponential moving averages to be sorted in the same order for two consecutive candles.
/// Uses ADX to confirm trend strength and supports optional stop-loss, take-profit, and trailing stop distances expressed in price units.
/// </summary>
public class TrueSortTrendStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _secondEmaLength;
private readonly StrategyParam<int> _thirdEmaLength;
private readonly StrategyParam<int> _fourthEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _adxPeriod;
private readonly StrategyParam<decimal> _adxThreshold;
private readonly StrategyParam<decimal> _stopLossDistance;
private readonly StrategyParam<decimal> _takeProfitDistance;
private readonly StrategyParam<decimal> _trailingStopDistance;
private readonly StrategyParam<decimal> _trailingStepDistance;
private ExponentialMovingAverage _fastEma;
private ExponentialMovingAverage _secondEma;
private ExponentialMovingAverage _thirdEma;
private ExponentialMovingAverage _fourthEma;
private ExponentialMovingAverage _slowEma;
private AverageDirectionalIndex _adx;
private decimal? _prevFast;
private decimal? _prevSecond;
private decimal? _prevThird;
private decimal? _prevFourth;
private decimal? _prevSlow;
private decimal _entryPrice;
private decimal _highestPrice;
private decimal _lowestPrice;
private int _positionDirection;
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Length of the fastest EMA.
/// </summary>
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
/// <summary>
/// Length of the second EMA.
/// </summary>
public int SecondEmaLength
{
get => _secondEmaLength.Value;
set => _secondEmaLength.Value = value;
}
/// <summary>
/// Length of the third EMA.
/// </summary>
public int ThirdEmaLength
{
get => _thirdEmaLength.Value;
set => _thirdEmaLength.Value = value;
}
/// <summary>
/// Length of the fourth EMA.
/// </summary>
public int FourthEmaLength
{
get => _fourthEmaLength.Value;
set => _fourthEmaLength.Value = value;
}
/// <summary>
/// Length of the slowest EMA.
/// </summary>
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
/// <summary>
/// ADX averaging period.
/// </summary>
public int AdxPeriod
{
get => _adxPeriod.Value;
set => _adxPeriod.Value = value;
}
/// <summary>
/// Minimum ADX value that confirms a strong trend.
/// </summary>
public decimal AdxThreshold
{
get => _adxThreshold.Value;
set => _adxThreshold.Value = value;
}
/// <summary>
/// Absolute stop-loss distance expressed in price units.
/// </summary>
public decimal StopLossDistance
{
get => _stopLossDistance.Value;
set => _stopLossDistance.Value = value;
}
/// <summary>
/// Absolute take-profit distance expressed in price units.
/// </summary>
public decimal TakeProfitDistance
{
get => _takeProfitDistance.Value;
set => _takeProfitDistance.Value = value;
}
/// <summary>
/// Trailing stop distance in price units.
/// </summary>
public decimal TrailingStopDistance
{
get => _trailingStopDistance.Value;
set => _trailingStopDistance.Value = value;
}
/// <summary>
/// Minimum price advance required before the trailing stop is activated or moved.
/// </summary>
public decimal TrailingStepDistance
{
get => _trailingStepDistance.Value;
set => _trailingStepDistance.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="TrueSortTrendStrategy"/> class.
/// </summary>
public TrueSortTrendStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type used for calculations", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA Length", "Period of the fastest EMA", "Moving Averages")
.SetOptimize(5, 20, 1);
_secondEmaLength = Param(nameof(SecondEmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("Second EMA Length", "Period of the second EMA", "Moving Averages")
.SetOptimize(10, 40, 2);
_thirdEmaLength = Param(nameof(ThirdEmaLength), 30)
.SetGreaterThanZero()
.SetDisplay("Third EMA Length", "Period of the third EMA", "Moving Averages")
.SetOptimize(30, 80, 5);
_fourthEmaLength = Param(nameof(FourthEmaLength), 40)
.SetGreaterThanZero()
.SetDisplay("Fourth EMA Length", "Period of the fourth EMA", "Moving Averages")
.SetOptimize(60, 140, 5);
_slowEmaLength = Param(nameof(SlowEmaLength), 50)
.SetGreaterThanZero()
.SetDisplay("Slow EMA Length", "Period of the slowest EMA", "Moving Averages")
.SetOptimize(150, 250, 5);
_adxPeriod = Param(nameof(AdxPeriod), 24)
.SetGreaterThanZero()
.SetDisplay("ADX Period", "Averaging period for the ADX indicator", "Indicators")
.SetOptimize(14, 40, 2);
_adxThreshold = Param(nameof(AdxThreshold), 10m)
.SetGreaterThanZero()
.SetDisplay("ADX Threshold", "Minimum ADX value to confirm trend strength", "Indicators")
.SetOptimize(15m, 35m, 5m);
_stopLossDistance = Param(nameof(StopLossDistance), 500m)
.SetRange(0m, 1m)
.SetDisplay("Stop Loss Distance", "Absolute distance for stop loss", "Risk")
.SetOptimize(0.001m, 0.01m, 0.001m);
_takeProfitDistance = Param(nameof(TakeProfitDistance), 1500m)
.SetRange(0m, 1m)
.SetDisplay("Take Profit Distance", "Absolute distance for take profit", "Risk")
.SetOptimize(0.002m, 0.03m, 0.002m);
_trailingStopDistance = Param(nameof(TrailingStopDistance), 300m)
.SetRange(0m, 1m)
.SetDisplay("Trailing Stop Distance", "Trailing stop distance in price units", "Risk")
.SetOptimize(0.0002m, 0.002m, 0.0002m);
_trailingStepDistance = Param(nameof(TrailingStepDistance), 100m)
.SetRange(0m, 1m)
.SetDisplay("Trailing Step Distance", "Additional advance before trailing stop adjustment", "Risk")
.SetOptimize(0m, 0.001m, 0.0001m);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSecond = null;
_prevThird = null;
_prevFourth = null;
_prevSlow = null;
ResetTradeState();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
_secondEma = new ExponentialMovingAverage { Length = SecondEmaLength };
_thirdEma = new ExponentialMovingAverage { Length = ThirdEmaLength };
_fourthEma = new ExponentialMovingAverage { Length = FourthEmaLength };
_slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
_adx = new AverageDirectionalIndex { Length = AdxPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandleRaw)
.Start();
var priceArea = CreateChartArea();
if (priceArea != null)
{
DrawCandles(priceArea, subscription);
DrawOwnTrades(priceArea);
}
}
private void ProcessCandleRaw(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var fastResult = _fastEma.Process(candle);
var secondResult = _secondEma.Process(candle);
var thirdResult = _thirdEma.Process(candle);
var fourthResult = _fourthEma.Process(candle);
var slowResult = _slowEma.Process(candle);
var adxResult = _adx.Process(candle);
if (!_slowEma.IsFormed || !_adx.IsFormed)
return;
if (fastResult.IsEmpty || secondResult.IsEmpty || thirdResult.IsEmpty || fourthResult.IsEmpty || slowResult.IsEmpty || adxResult.IsEmpty)
return;
var fast = fastResult.ToDecimal();
var second = secondResult.ToDecimal();
var third = thirdResult.ToDecimal();
var fourth = fourthResult.ToDecimal();
var slow = slowResult.ToDecimal();
var adxData = (AverageDirectionalIndexValue)adxResult;
var adxValue = adxData.MovingAverage ?? 0m;
if (_prevFast is null || _prevSecond is null || _prevThird is null || _prevFourth is null || _prevSlow is null)
{
UpdatePreviousValues(fast, second, third, fourth, slow);
return;
}
var ascendingCurrent = fast > second && second > third && third > fourth && fourth > slow;
var descendingCurrent = fast < second && second < third && third < fourth && fourth < slow;
var ascendingPrevious = _prevFast > _prevSecond && _prevSecond > _prevThird && _prevThird > _prevFourth && _prevFourth > _prevSlow;
var descendingPrevious = _prevFast < _prevSecond && _prevSecond < _prevThird && _prevThird < _prevFourth && _prevFourth < _prevSlow;
var openLongSignal = adxValue > AdxThreshold && ascendingCurrent && ascendingPrevious;
var openShortSignal = adxValue > AdxThreshold && descendingCurrent && descendingPrevious;
var breakLongStack = !ascendingCurrent;
var breakShortStack = !descendingCurrent;
var position = Position;
if (position == 0 && _positionDirection != 0)
ResetTradeState();
if (position > 0)
{
_highestPrice = _highestPrice == 0m ? candle.HighPrice : Math.Max(_highestPrice, candle.HighPrice);
_lowestPrice = candle.LowPrice;
var exitVolume = Math.Abs(position);
var shouldExit = false;
if (!shouldExit && StopLossDistance > 0m && candle.LowPrice <= _entryPrice - StopLossDistance)
shouldExit = true;
if (!shouldExit && TakeProfitDistance > 0m && candle.HighPrice >= _entryPrice + TakeProfitDistance)
shouldExit = true;
if (!shouldExit && TrailingStopDistance > 0m)
{
var activation = TrailingStopDistance + Math.Max(0m, TrailingStepDistance);
if (_highestPrice - _entryPrice >= activation)
{
var trailingLevel = _highestPrice - TrailingStopDistance;
if (candle.ClosePrice <= trailingLevel)
shouldExit = true;
}
}
if (!shouldExit && breakLongStack)
shouldExit = true;
if (shouldExit && exitVolume > 0)
{
SellMarket(exitVolume);
ResetTradeState();
position = 0;
}
}
else if (position < 0)
{
_lowestPrice = _lowestPrice == 0m ? candle.LowPrice : Math.Min(_lowestPrice, candle.LowPrice);
_highestPrice = candle.HighPrice;
var exitVolume = Math.Abs(position);
var shouldExit = false;
if (!shouldExit && StopLossDistance > 0m && candle.HighPrice >= _entryPrice + StopLossDistance)
shouldExit = true;
if (!shouldExit && TakeProfitDistance > 0m && candle.LowPrice <= _entryPrice - TakeProfitDistance)
shouldExit = true;
if (!shouldExit && TrailingStopDistance > 0m)
{
var activation = TrailingStopDistance + Math.Max(0m, TrailingStepDistance);
if (_entryPrice - _lowestPrice >= activation)
{
var trailingLevel = _lowestPrice + TrailingStopDistance;
if (candle.ClosePrice >= trailingLevel)
shouldExit = true;
}
}
if (!shouldExit && breakShortStack)
shouldExit = true;
if (shouldExit && exitVolume > 0)
{
BuyMarket(exitVolume);
ResetTradeState();
position = 0;
}
}
if (position <= 0 && openLongSignal)
{
var volumeToBuy = Volume + Math.Max(0m, -position);
if (volumeToBuy > 0)
{
BuyMarket(volumeToBuy);
_entryPrice = candle.ClosePrice;
_highestPrice = candle.HighPrice;
_lowestPrice = candle.LowPrice;
_positionDirection = 1;
}
}
else if (position >= 0 && openShortSignal)
{
var volumeToSell = Volume + Math.Max(0m, position);
if (volumeToSell > 0)
{
SellMarket(volumeToSell);
_entryPrice = candle.ClosePrice;
_highestPrice = candle.HighPrice;
_lowestPrice = candle.LowPrice;
_positionDirection = -1;
}
}
if (Position == 0 && _positionDirection != 0)
ResetTradeState();
UpdatePreviousValues(fast, second, third, fourth, slow);
}
private void UpdatePreviousValues(decimal fast, decimal second, decimal third, decimal fourth, decimal slow)
{
_prevFast = fast;
_prevSecond = second;
_prevThird = third;
_prevFourth = fourth;
_prevSlow = slow;
}
private void ResetTradeState()
{
_entryPrice = 0m;
_highestPrice = 0m;
_lowestPrice = 0m;
_positionDirection = 0;
}
}
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 ExponentialMovingAverage, AverageDirectionalIndex, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class true_sort_trend_strategy(Strategy):
"""Five EMA alignment with ADX confirmation, SL/TP and trailing stop."""
def __init__(self):
super(true_sort_trend_strategy, self).__init__()
self._fast_len = self.Param("FastEmaLength", 10).SetGreaterThanZero().SetDisplay("Fast EMA", "Fastest EMA", "MAs")
self._second_len = self.Param("SecondEmaLength", 20).SetGreaterThanZero().SetDisplay("2nd EMA", "Second EMA", "MAs")
self._third_len = self.Param("ThirdEmaLength", 30).SetGreaterThanZero().SetDisplay("3rd EMA", "Third EMA", "MAs")
self._fourth_len = self.Param("FourthEmaLength", 40).SetGreaterThanZero().SetDisplay("4th EMA", "Fourth EMA", "MAs")
self._slow_len = self.Param("SlowEmaLength", 50).SetGreaterThanZero().SetDisplay("Slow EMA", "Slowest EMA", "MAs")
self._adx_period = self.Param("AdxPeriod", 24).SetGreaterThanZero().SetDisplay("ADX Period", "ADX averaging", "Indicators")
self._adx_threshold = self.Param("AdxThreshold", 10.0).SetGreaterThanZero().SetDisplay("ADX Threshold", "Min ADX for trend", "Indicators")
self._sl_dist = self.Param("StopLossDistance", 500.0).SetDisplay("Stop Loss", "SL distance", "Risk")
self._tp_dist = self.Param("TakeProfitDistance", 1500.0).SetDisplay("Take Profit", "TP distance", "Risk")
self._trail_dist = self.Param("TrailingStopDistance", 300.0).SetDisplay("Trailing Stop", "Trail distance", "Risk")
self._trail_step = self.Param("TrailingStepDistance", 100.0).SetDisplay("Trailing Step", "Trail step", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "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(true_sort_trend_strategy, self).OnReseted()
self._prev = [0, 0, 0, 0, 0]
self._has_prev = False
self._entry_price = 0
self._highest = 0
self._lowest = 0
self._pos_dir = 0
def OnStarted2(self, time):
super(true_sort_trend_strategy, self).OnStarted2(time)
self._prev = [0, 0, 0, 0, 0]
self._has_prev = False
self._entry_price = 0
self._highest = 0
self._lowest = 0
self._pos_dir = 0
self._ema1 = ExponentialMovingAverage()
self._ema1.Length = self._fast_len.Value
self._ema2 = ExponentialMovingAverage()
self._ema2.Length = self._second_len.Value
self._ema3 = ExponentialMovingAverage()
self._ema3.Length = self._third_len.Value
self._ema4 = ExponentialMovingAverage()
self._ema4.Length = self._fourth_len.Value
self._ema5 = ExponentialMovingAverage()
self._ema5.Length = self._slow_len.Value
self._adx = AverageDirectionalIndex()
self._adx.Length = self._adx_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self._ema1, self._ema2, self._ema3, self._ema4, self._ema5, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle, v1, v2, v3, v4, v5):
if candle.State != CandleStates.Finished:
return
# Process ADX manually
civ = CandleIndicatorValue(self._adx, candle)
civ.IsFinal = True
adx_result = self._adx.Process(civ)
if not self._adx.IsFormed:
return
adx_val = float(adx_result.MovingAverage) if not adx_result.IsEmpty and adx_result.MovingAverage is not None else 0
vals = [float(v1), float(v2), float(v3), float(v4), float(v5)]
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
if not self._has_prev:
self._prev = vals[:]
self._has_prev = True
return
asc_cur = vals[0] > vals[1] and vals[1] > vals[2] and vals[2] > vals[3] and vals[3] > vals[4]
desc_cur = vals[0] < vals[1] and vals[1] < vals[2] and vals[2] < vals[3] and vals[3] < vals[4]
asc_prev = self._prev[0] > self._prev[1] and self._prev[1] > self._prev[2] and self._prev[2] > self._prev[3] and self._prev[3] > self._prev[4]
desc_prev = self._prev[0] < self._prev[1] and self._prev[1] < self._prev[2] and self._prev[2] < self._prev[3] and self._prev[3] < self._prev[4]
long_signal = adx_val > self._adx_threshold.Value and asc_cur and asc_prev
short_signal = adx_val > self._adx_threshold.Value and desc_cur and desc_prev
sl = self._sl_dist.Value
tp = self._tp_dist.Value
trail = self._trail_dist.Value
trail_s = self._trail_step.Value
# Exit management
if self.Position > 0:
if self._highest == 0:
self._highest = high
else:
self._highest = max(self._highest, high)
should_exit = False
if sl > 0 and low <= self._entry_price - sl:
should_exit = True
if not should_exit and tp > 0 and high >= self._entry_price + tp:
should_exit = True
if not should_exit and trail > 0:
activation = trail + max(0, trail_s)
if self._highest - self._entry_price >= activation:
trail_level = self._highest - trail
if close <= trail_level:
should_exit = True
if not should_exit and not asc_cur:
should_exit = True
if should_exit:
self.SellMarket()
self._reset_trade()
elif self.Position < 0:
if self._lowest == 0:
self._lowest = low
else:
self._lowest = min(self._lowest, low)
should_exit = False
if sl > 0 and high >= self._entry_price + sl:
should_exit = True
if not should_exit and tp > 0 and low <= self._entry_price - tp:
should_exit = True
if not should_exit and trail > 0:
activation = trail + max(0, trail_s)
if self._entry_price - self._lowest >= activation:
trail_level = self._lowest + trail
if close >= trail_level:
should_exit = True
if not should_exit and not desc_cur:
should_exit = True
if should_exit:
self.BuyMarket()
self._reset_trade()
# Entries
if long_signal and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._highest = high
self._lowest = low
self._pos_dir = 1
elif short_signal and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._highest = high
self._lowest = low
self._pos_dir = -1
self._prev = vals[:]
def _reset_trade(self):
self._entry_price = 0
self._highest = 0
self._lowest = 0
self._pos_dir = 0
def CreateClone(self):
return true_sort_trend_strategy()