Стратегия Chaos Trader Lite
Стратегия Chaos Trader Lite воспроизводит три техники входа Билла Уильямса («три мудреца») с использованием высокоуровневого API StockSharp. На каждой завершённой свече выбранного таймфрейма (по умолчанию 1 час) выполняются проверки и выставляются отложенные ордера при выполнении любого из условий:
- Первый мудрец — дивергентный бар: определяет бычьи или медвежьи дивергентные свечи и требует минимальный зазор между ценой и линией губ Alligator.
- Второй мудрец — ускорение Awesome Oscillator: ожидает пять последовательных значений индикатора, подтверждающих нарастание импульса.
- Третий мудрец — пробой фрактала: подтверждает фрактал двумя барами ранее и проверяет, что цена находится достаточно далеко от линии зубов Alligator, прежде чем подготовить ордер на пробой.
При появлении сигнала на покупку стратегия отменяет активные sell stop, закрывает короткие позиции, ставит новый buy stop чуть выше максимума свечи и фиксирует защитный стоп ниже минимума. Для продаж выполняется зеркальная последовательность. Защитные уровни проверяются на каждой свече: при пересечении цены открытая позиция закрывается рыночным ордером.
Индикаторы и расчёты
- Губы Alligator: сглаженная средняя (SMMA) длиной 5 по медианной цене со смещением на три бара вперёд. Значения сохраняются в очереди, чтобы смещение совпадало с реализацией MetaTrader.
- Зубы Alligator: сглаженная средняя длиной 8 по медиане со смещением на пять баров вперёд; используется как фильтр третьего мудреца.
- Awesome Oscillator: встроенный индикатор (разница SMA 5 и SMA 34 от медианы) формирует последовательность импульса для второго мудреца.
- Фракталы: анализируется свеча, находящаяся на две позиции левее текущей. Фрактал подтверждается, если её максимум (минимум) выше (ниже) максимумов и минимумов двух соседних баров.
Торговая логика
- Подписка на заданный тип свечей и обработка только завершённых баров.
- Обновление индикаторов Alligator и Awesome Oscillator и сохранение смещённых значений.
- Проверка условий мудрецов:
- Дивергентный бар должен закрыться в верхней (для покупок) или нижней (для продаж) половине свечи, а расстояние до губ превышать
MagnitudePips * PriceStep. - Ускорение AO требует пяти значений:
AO[1] > AO[2] > AO[3] > AO[4]иAO[4] < AO[5]для лонга и зеркально для шорта. - Пробой фрактала требует закрытия выше (ниже) подтверждённого фрактала и выше (ниже) зубов Alligator плюс пороговое расстояние.
- Дивергентный бар должен закрыться в верхней (для покупок) или нижней (для продаж) половине свечи, а расстояние до губ превышать
- При выполнении условия регистрируется
BuyStopилиSellStopобъёмомVolumeна уровне максимума свечи плюс один шаг цены (или минимума минус шаг). Противоположные стопы отменяются, противоположные позиции закрываются. - Обновляются защитные стопы: для длинных они подтягиваются вверх, для коротких опускаются вниз. При пробое уровня позиция закрывается по рынку.
Параметры
MagnitudePips(по умолчанию 10) — минимальное расстояние в пунктах между дивергентной свечой и губами Alligator.UseFirstWiseMan(по умолчанию true) — включение/отключение входа по дивергентным барам.UseSecondWiseMan(по умолчанию true) — включение/отключение входа по ускорению Awesome Oscillator.UseThirdWiseMan(по умолчанию true) — включение/отключение входа по пробою фрактала.Volume(по умолчанию 0.01) — объём стоп-ордеров.CandleType(по умолчанию 1 час) — тип свечей, обрабатываемых стратегией.
Примечания
- Проверки bid/ask из оригинального MQL4 заменены использованием цены закрытия свечи.
- Контроль маржи и валидаторы объёма из MetaTrader опущены, поскольку в StockSharp проверка заявок выполняется на стороне движка.
- Отложенные ордера противоположного направления отменяются при появлении нового сигнала, что соответствует поведению функции
CloseAllв исходном советнике.
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>
/// Chaos Trader Lite strategy implementing Bill Williams' three wise men entry concepts.
/// Uses market orders when divergent bars, Awesome Oscillator accelerations or confirmed fractals appear.
/// </summary>
public class ChaosTraderLiteStrategy : Strategy
{
private readonly StrategyParam<int> _lipsShift;
private readonly StrategyParam<int> _teethShift;
private readonly StrategyParam<int> _magnitudePips;
private readonly StrategyParam<bool> _useFirstWiseMan;
private readonly StrategyParam<bool> _useSecondWiseMan;
private readonly StrategyParam<bool> _useThirdWiseMan;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _lipsSmma = null!;
private SimpleMovingAverage _teethSmma = null!;
private AwesomeOscillator _awesomeOscillator = null!;
private readonly List<decimal> _lipsShiftQueue = new();
private readonly List<decimal> _teethShiftQueue = new();
private CandleInfo? _bar0;
private CandleInfo? _bar1;
private CandleInfo? _bar2;
private CandleInfo? _bar3;
private CandleInfo? _bar4;
private decimal? _lips0;
private decimal? _teeth0;
private decimal? _teeth1;
private decimal? _ao0;
private decimal? _ao1;
private decimal? _ao2;
private decimal? _ao3;
private decimal? _ao4;
private decimal? _ao5;
private decimal? _longStopLoss;
private decimal? _shortStopLoss;
// Pending entry prices for stop-like behavior
private decimal? _pendingBuyPrice;
private decimal? _pendingSellPrice;
private decimal? _pendingBuyStop;
private decimal? _pendingSellStop;
/// <summary>
/// Magnitude threshold in pips between price and Alligator lips.
/// </summary>
public int MagnitudePips
{
get => _magnitudePips.Value;
set => _magnitudePips.Value = value;
}
/// <summary>
/// Number of candles used to shift the Alligator lips line.
/// </summary>
public int LipsShift
{
get => _lipsShift.Value;
set => _lipsShift.Value = value;
}
/// <summary>
/// Number of candles used to shift the Alligator teeth line.
/// </summary>
public int TeethShift
{
get => _teethShift.Value;
set => _teethShift.Value = value;
}
/// <summary>
/// Enable the first wise man divergent bar setup.
/// </summary>
public bool UseFirstWiseMan
{
get => _useFirstWiseMan.Value;
set => _useFirstWiseMan.Value = value;
}
/// <summary>
/// Enable the second wise man Awesome Oscillator acceleration setup.
/// </summary>
public bool UseSecondWiseMan
{
get => _useSecondWiseMan.Value;
set => _useSecondWiseMan.Value = value;
}
/// <summary>
/// Enable the third wise man fractal breakout setup.
/// </summary>
public bool UseThirdWiseMan
{
get => _useThirdWiseMan.Value;
set => _useThirdWiseMan.Value = value;
}
/// <summary>
/// Candle type processed by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="ChaosTraderLiteStrategy"/>.
/// </summary>
public ChaosTraderLiteStrategy()
{
_magnitudePips = Param(nameof(MagnitudePips), 10)
.SetGreaterThanZero()
.SetDisplay("Magnitude", "Distance from lips in pips", "General");
_lipsShift = Param(nameof(LipsShift), 3)
.SetNotNegative()
.SetDisplay("Lips Shift", "Shift applied to Alligator lips", "Alligator");
_teethShift = Param(nameof(TeethShift), 5)
.SetNotNegative()
.SetDisplay("Teeth Shift", "Shift applied to Alligator teeth", "Alligator");
_useFirstWiseMan = Param(nameof(UseFirstWiseMan), true)
.SetDisplay("First Wise Man", "Enable divergent bar setup", "General");
_useSecondWiseMan = Param(nameof(UseSecondWiseMan), true)
.SetDisplay("Second Wise Man", "Enable Awesome Oscillator setup", "General");
_useThirdWiseMan = Param(nameof(UseThirdWiseMan), true)
.SetDisplay("Third Wise Man", "Enable fractal breakout setup", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bar0 = _bar1 = _bar2 = _bar3 = _bar4 = null;
_lipsShiftQueue.Clear();
_teethShiftQueue.Clear();
_lips0 = null;
_teeth0 = null;
_teeth1 = null;
_ao0 = null;
_ao1 = null;
_ao2 = null;
_ao3 = null;
_ao4 = null;
_ao5 = null;
_longStopLoss = null;
_shortStopLoss = null;
_pendingBuyPrice = null;
_pendingSellPrice = null;
_pendingBuyStop = null;
_pendingSellStop = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_lipsSmma = new SimpleMovingAverage { Length = 5 };
_teethSmma = new SimpleMovingAverage { Length = 8 };
_awesomeOscillator = new AwesomeOscillator { ShortMa = { Length = 5 }, LongMa = { Length = 34 } };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _lipsSmma);
DrawIndicator(area, _teethSmma);
DrawIndicator(area, _awesomeOscillator);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Check pending stop-like entries first
CheckPendingEntries(candle);
UpdateBarHistory(candle);
var median = (candle.HighPrice + candle.LowPrice) / 2m;
var candleInput = new CandleIndicatorValue(_lipsSmma, candle);
var lipsValue = _lipsSmma.Process(new DecimalIndicatorValue(_lipsSmma, median, candle.ServerTime) { IsFinal = true });
var teethValue = _teethSmma.Process(new DecimalIndicatorValue(_teethSmma, median, candle.ServerTime) { IsFinal = true });
var awesomeValue = _awesomeOscillator.Process(new CandleIndicatorValue(_awesomeOscillator, candle));
if (lipsValue.IsFinal)
{
var lips = lipsValue.ToDecimal();
_lipsShiftQueue.Add(lips);
if (_lipsShiftQueue.Count > LipsShift)
{
_lips0 = _lipsShiftQueue[0];
try { _lipsShiftQueue.RemoveAt(0); } catch { }
}
}
if (teethValue.IsFinal)
{
var teeth = teethValue.ToDecimal();
_teethShiftQueue.Add(teeth);
if (_teethShiftQueue.Count > TeethShift)
{
_teeth1 = _teeth0;
_teeth0 = _teethShiftQueue[0];
try { _teethShiftQueue.RemoveAt(0); } catch { }
}
}
if (awesomeValue.IsFinal)
{
var ao = awesomeValue.ToDecimal();
_ao5 = _ao4;
_ao4 = _ao3;
_ao3 = _ao2;
_ao2 = _ao1;
_ao1 = _ao0;
_ao0 = ao;
}
var upFractal = GetUpFractal();
var downFractal = GetDownFractal();
if (_lipsSmma.IsFormed && _teethSmma.IsFormed)
EvaluateSignals(candle, upFractal, downFractal);
UpdateProtection(candle);
}
private void CheckPendingEntries(ICandleMessage candle)
{
// Simulate buy stop: if candle high reaches or exceeds pending buy price, enter long
if (_pendingBuyPrice is decimal buyPrice && candle.HighPrice >= buyPrice)
{
if (Position <= 0)
{
if (Position < 0)
{
BuyMarket();
_shortStopLoss = null;
}
if (Volume > 0)
{
BuyMarket();
_longStopLoss = _pendingBuyStop;
}
}
_pendingBuyPrice = null;
_pendingBuyStop = null;
}
// Simulate sell stop: if candle low reaches or goes below pending sell price, enter short
if (_pendingSellPrice is decimal sellPrice && candle.LowPrice <= sellPrice)
{
if (Position >= 0)
{
if (Position > 0)
{
SellMarket();
_longStopLoss = null;
}
if (Volume > 0)
{
SellMarket();
_shortStopLoss = _pendingSellStop;
}
}
_pendingSellPrice = null;
_pendingSellStop = null;
}
}
private void EvaluateSignals(ICandleMessage candle, decimal? upFractal, decimal? downFractal)
{
if (_bar0 is not CandleInfo current || _bar1 is not CandleInfo previous)
return;
var point = Security?.PriceStep ?? 1m;
var magnitudeThreshold = MagnitudePips * point;
if (UseFirstWiseMan && _lips0 is decimal lips)
{
if (IsBullishDivergent(current, previous))
{
var distance = lips - current.High;
if (distance > magnitudeThreshold)
PlaceBuySetup(current, point);
}
if (IsBearishDivergent(current, previous))
{
var distance = current.Low - lips;
if (distance > magnitudeThreshold)
PlaceSellSetup(current, point);
}
}
if (UseSecondWiseMan && _ao1.HasValue && _ao2.HasValue && _ao3.HasValue && _ao4.HasValue && _ao5.HasValue)
{
var currentAo = _ao1.Value;
var bar2Ao = _ao2.Value;
var bar3Ao = _ao3.Value;
var bar4Ao = _ao4.Value;
var bar5Ao = _ao5.Value;
var bullishAcceleration = currentAo > bar2Ao && bar2Ao > bar3Ao && bar3Ao > bar4Ao && bar4Ao < bar5Ao;
if (bullishAcceleration)
PlaceBuySetup(current, point);
var bearishAcceleration = currentAo < bar2Ao && bar2Ao < bar3Ao && bar3Ao < bar4Ao && bar4Ao > bar5Ao;
if (bearishAcceleration)
PlaceSellSetup(current, point);
}
if (UseThirdWiseMan && _teeth0.HasValue)
{
var teeth = _teeth0.Value;
var offset = MagnitudePips * point;
if (upFractal.HasValue && candle.ClosePrice > teeth + offset)
PlaceBuySetup(current, point);
if (downFractal.HasValue && candle.ClosePrice < teeth - offset)
PlaceSellSetup(current, point);
}
}
private void UpdateProtection(ICandleMessage candle)
{
if (Position > 0 && _longStopLoss is decimal longStop)
{
if (candle.LowPrice <= longStop)
{
SellMarket();
_longStopLoss = null;
}
}
else if (Position < 0 && _shortStopLoss is decimal shortStop)
{
if (candle.HighPrice >= shortStop)
{
BuyMarket();
_shortStopLoss = null;
}
}
}
private void PlaceBuySetup(CandleInfo bar, decimal point)
{
if (Volume <= 0)
return;
var entryPrice = bar.High + point;
if (entryPrice <= 0m)
return;
var stopPrice = bar.Low - point;
// Cancel pending sell
_pendingSellPrice = null;
_pendingSellStop = null;
// Set pending buy entry (simulates buy stop order)
_pendingBuyPrice = entryPrice;
_pendingBuyStop = stopPrice;
}
private void PlaceSellSetup(CandleInfo bar, decimal point)
{
if (Volume <= 0)
return;
var entryPrice = bar.Low - point;
if (entryPrice <= 0m)
return;
var stopPrice = bar.High + point;
// Cancel pending buy
_pendingBuyPrice = null;
_pendingBuyStop = null;
// Set pending sell entry (simulates sell stop order)
_pendingSellPrice = entryPrice;
_pendingSellStop = stopPrice;
}
private static bool IsBullishDivergent(CandleInfo current, CandleInfo previous)
{
var median = (current.High + current.Low) / 2m;
return current.Low < previous.Low && current.Close > median;
}
private static bool IsBearishDivergent(CandleInfo current, CandleInfo previous)
{
var median = (current.High + current.Low) / 2m;
return current.High > previous.High && current.Close < median;
}
private decimal? GetUpFractal()
{
if (_bar0 is not CandleInfo bar0 || _bar1 is not CandleInfo bar1 || _bar2 is not CandleInfo bar2 ||
_bar3 is not CandleInfo bar3 || _bar4 is not CandleInfo bar4)
return null;
return bar2.High > bar3.High && bar2.High > bar4.High && bar2.High > bar1.High && bar2.High > bar0.High
? bar2.High
: null;
}
private decimal? GetDownFractal()
{
if (_bar0 is not CandleInfo bar0 || _bar1 is not CandleInfo bar1 || _bar2 is not CandleInfo bar2 ||
_bar3 is not CandleInfo bar3 || _bar4 is not CandleInfo bar4)
return null;
return bar2.Low < bar3.Low && bar2.Low < bar4.Low && bar2.Low < bar1.Low && bar2.Low < bar0.Low
? bar2.Low
: null;
}
private void UpdateBarHistory(ICandleMessage candle)
{
_bar4 = _bar3;
_bar3 = _bar2;
_bar2 = _bar1;
_bar1 = _bar0;
_bar0 = new CandleInfo
{
Open = candle.OpenPrice,
High = candle.HighPrice,
Low = candle.LowPrice,
Close = candle.ClosePrice
};
}
private struct CandleInfo
{
public decimal Open { get; init; }
public decimal High { get; init; }
public decimal Low { get; init; }
public decimal Close { get; init; }
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import (
SimpleMovingAverage, AwesomeOscillator, CandleIndicatorValue
)
from indicator_extensions import *
class chaos_trader_lite_strategy(Strategy):
"""Chaos Trader Lite: Bill Williams three wise men with divergent bars, AO and fractals."""
def __init__(self):
super(chaos_trader_lite_strategy, self).__init__()
self._magnitude_pips = self.Param("MagnitudePips", 10) \
.SetGreaterThanZero() \
.SetDisplay("Magnitude", "Distance from lips in pips", "General")
self._lips_shift = self.Param("LipsShift", 3) \
.SetDisplay("Lips Shift", "Shift applied to Alligator lips", "Alligator")
self._teeth_shift = self.Param("TeethShift", 5) \
.SetDisplay("Teeth Shift", "Shift applied to Alligator teeth", "Alligator")
self._use_first = self.Param("UseFirstWiseMan", True) \
.SetDisplay("First Wise Man", "Enable divergent bar setup", "General")
self._use_second = self.Param("UseSecondWiseMan", True) \
.SetDisplay("Second Wise Man", "Enable Awesome Oscillator setup", "General")
self._use_third = self.Param("UseThirdWiseMan", True) \
.SetDisplay("Third Wise Man", "Enable fractal breakout setup", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._bars = [None] * 5 # bar0..bar4, each = (o, h, lo, c)
self._lips_queue = []
self._teeth_queue = []
self._lips0 = None
self._teeth0 = None
self._teeth1 = None
self._ao_hist = [None] * 6 # ao0..ao5
self._long_sl = None
self._short_sl = None
self._pending_buy = None
self._pending_sell = None
self._pending_buy_stop = None
self._pending_sell_stop = None
@property
def MagnitudePips(self):
return int(self._magnitude_pips.Value)
@property
def LipsShift(self):
return int(self._lips_shift.Value)
@property
def TeethShift(self):
return int(self._teeth_shift.Value)
@property
def UseFirstWiseMan(self):
return self._use_first.Value
@property
def UseSecondWiseMan(self):
return self._use_second.Value
@property
def UseThirdWiseMan(self):
return self._use_third.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(chaos_trader_lite_strategy, self).OnStarted2(time)
self._bars = [None] * 5
self._lips_queue = []
self._teeth_queue = []
self._lips0 = None
self._teeth0 = None
self._teeth1 = None
self._ao_hist = [None] * 6
self._long_sl = None
self._short_sl = None
self._pending_buy = None
self._pending_sell = None
self._pending_buy_stop = None
self._pending_sell_stop = None
self._lips_sma = SimpleMovingAverage()
self._lips_sma.Length = 5
self._teeth_sma = SimpleMovingAverage()
self._teeth_sma.Length = 8
self._ao = AwesomeOscillator()
self._ao.ShortMa.Length = 5
self._ao.LongMa.Length = 34
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
o = float(candle.OpenPrice)
c = float(candle.ClosePrice)
# Check pending entries
self._check_pending(candle)
# Update bar history
self._bars[4] = self._bars[3]
self._bars[3] = self._bars[2]
self._bars[2] = self._bars[1]
self._bars[1] = self._bars[0]
self._bars[0] = (o, h, lo, c)
median = (h + lo) / 2.0
# Lips
lips_val = process_float(self._lips_sma, Decimal(median), candle.ServerTime, True)
if lips_val.IsFinal:
lv = float(lips_val.Value)
self._lips_queue.append(lv)
if len(self._lips_queue) > self.LipsShift:
self._lips0 = self._lips_queue.pop(0)
# Teeth
teeth_val = process_float(self._teeth_sma, Decimal(median), candle.ServerTime, True)
if teeth_val.IsFinal:
tv = float(teeth_val.Value)
self._teeth_queue.append(tv)
if len(self._teeth_queue) > self.TeethShift:
self._teeth1 = self._teeth0
self._teeth0 = self._teeth_queue.pop(0)
# AO
ao_val = self._ao.Process(CandleIndicatorValue(self._ao, candle))
if ao_val.IsFinal:
av = float(ao_val.Value)
self._ao_hist[5] = self._ao_hist[4]
self._ao_hist[4] = self._ao_hist[3]
self._ao_hist[3] = self._ao_hist[2]
self._ao_hist[2] = self._ao_hist[1]
self._ao_hist[1] = self._ao_hist[0]
self._ao_hist[0] = av
up_fractal = self._get_up_fractal()
down_fractal = self._get_down_fractal()
if self._lips_sma.IsFormed and self._teeth_sma.IsFormed:
self._evaluate_signals(candle, up_fractal, down_fractal)
self._update_protection(candle)
def _check_pending(self, candle):
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
if self._pending_buy is not None and h >= self._pending_buy:
if self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self._short_sl = None
self.BuyMarket()
self._long_sl = self._pending_buy_stop
self._pending_buy = None
self._pending_buy_stop = None
if self._pending_sell is not None and lo <= self._pending_sell:
if self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self._long_sl = None
self.SellMarket()
self._short_sl = self._pending_sell_stop
self._pending_sell = None
self._pending_sell_stop = None
def _evaluate_signals(self, candle, up_fractal, down_fractal):
cur = self._bars[0]
prev = self._bars[1]
if cur is None or prev is None:
return
sec = self.Security
point = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None and float(sec.PriceStep) > 0 else 1.0
mag_thresh = self.MagnitudePips * point
if self.UseFirstWiseMan and self._lips0 is not None:
lips = self._lips0
if self._is_bull_div(cur, prev):
dist = lips - cur[1]
if dist > mag_thresh:
self._place_buy(cur, point)
if self._is_bear_div(cur, prev):
dist = cur[2] - lips
if dist > mag_thresh:
self._place_sell(cur, point)
if self.UseSecondWiseMan:
ao1 = self._ao_hist[1]
ao2 = self._ao_hist[2]
ao3 = self._ao_hist[3]
ao4 = self._ao_hist[4]
ao5 = self._ao_hist[5]
if ao1 is not None and ao2 is not None and ao3 is not None and ao4 is not None and ao5 is not None:
if ao1 > ao2 and ao2 > ao3 and ao3 > ao4 and ao4 < ao5:
self._place_buy(cur, point)
if ao1 < ao2 and ao2 < ao3 and ao3 < ao4 and ao4 > ao5:
self._place_sell(cur, point)
if self.UseThirdWiseMan and self._teeth0 is not None:
teeth = self._teeth0
offset = self.MagnitudePips * point
c = float(candle.ClosePrice)
if up_fractal is not None and c > teeth + offset:
self._place_buy(cur, point)
if down_fractal is not None and c < teeth - offset:
self._place_sell(cur, point)
def _is_bull_div(self, cur, prev):
median = (cur[1] + cur[2]) / 2.0
return cur[2] < prev[2] and cur[3] > median
def _is_bear_div(self, cur, prev):
median = (cur[1] + cur[2]) / 2.0
return cur[1] > prev[1] and cur[3] < median
def _place_buy(self, bar, point):
entry = bar[1] + point
if entry <= 0:
return
stop = bar[2] - point
self._pending_sell = None
self._pending_sell_stop = None
self._pending_buy = entry
self._pending_buy_stop = stop
def _place_sell(self, bar, point):
entry = bar[2] - point
if entry <= 0:
return
stop = bar[1] + point
self._pending_buy = None
self._pending_buy_stop = None
self._pending_sell = entry
self._pending_sell_stop = stop
def _update_protection(self, candle):
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
if self.Position > 0 and self._long_sl is not None:
if lo <= self._long_sl:
self.SellMarket()
self._long_sl = None
elif self.Position < 0 and self._short_sl is not None:
if h >= self._short_sl:
self.BuyMarket()
self._short_sl = None
def _get_up_fractal(self):
b = self._bars
if b[0] is None or b[1] is None or b[2] is None or b[3] is None or b[4] is None:
return None
if b[2][1] > b[3][1] and b[2][1] > b[4][1] and b[2][1] > b[1][1] and b[2][1] > b[0][1]:
return b[2][1]
return None
def _get_down_fractal(self):
b = self._bars
if b[0] is None or b[1] is None or b[2] is None or b[3] is None or b[4] is None:
return None
if b[2][2] < b[3][2] and b[2][2] < b[4][2] and b[2][2] < b[1][2] and b[2][2] < b[0][2]:
return b[2][2]
return None
def OnReseted(self):
super(chaos_trader_lite_strategy, self).OnReseted()
self._bars = [None] * 5
self._lips_queue = []
self._teeth_queue = []
self._lips0 = None
self._teeth0 = None
self._teeth1 = None
self._ao_hist = [None] * 6
self._long_sl = None
self._short_sl = None
self._pending_buy = None
self._pending_sell = None
self._pending_buy_stop = None
self._pending_sell_stop = None
def CreateClone(self):
return chaos_trader_lite_strategy()