Стратегия 20/200 Expert v4.2 AntS
Стратегия открывает не более одной позиции в день в заданный час. Она сравнивает цену открытия двух прошедших баров (T1 и T2). Если более ранний бар выше позднего на DeltaShort пунктов, открывается короткая позиция. Если поздний бар выше на DeltaLong пунктов, открывается длинная позиция.
Объём позиции может быть фиксированным или рассчитываться автоматически исходя из баланса. Если баланс уменьшился по сравнению с предыдущей сделкой, объём умножается на BigLotSize.
Каждая сделка имеет собственные take-profit и stop-loss в пунктах. Также максимальное время удержания MaxOpenTime закрывает позицию по истечении указанного количества часов.
Параметры
CandleType– таймфрейм обрабатываемых свечей (по умолчанию 1 час).TradeHour– час суток для проверки условий входа.T1,T2– сдвиги баров для сравнения цен открытия.DeltaLong,DeltaShort– минимальная разница цен открытия в пунктах.TakeProfitLong,StopLossLong– защита для длинных сделок в пунктах.TakeProfitShort,StopLossShort– защита для коротких сделок в пунктах.Lot– базовый торговый объём.AutoLot– включить автоматический расчёт объёма.BigLotSize– множитель после убыточной сделки.MaxOpenTime– максимальное время удержания позиции в часах.
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>
/// "20/200 expert v4.2 AntS" strategy.
/// Opens trades based on the difference between two past open prices.
/// Closes positions by stop-loss, take-profit or time.
/// </summary>
public class Twenty200ExpertAutoLotStrategy : Strategy
{
private readonly StrategyParam<int> _takeProfitLong;
private readonly StrategyParam<int> _stopLossLong;
private readonly StrategyParam<int> _takeProfitShort;
private readonly StrategyParam<int> _stopLossShort;
private readonly StrategyParam<int> _t1;
private readonly StrategyParam<int> _t2;
private readonly StrategyParam<int> _deltaLong;
private readonly StrategyParam<int> _deltaShort;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _opens = new();
private decimal _stopPrice;
private decimal _takePrice;
private DateTimeOffset _entryTime;
private bool _isLong;
public int TakeProfitLong { get => _takeProfitLong.Value; set => _takeProfitLong.Value = value; }
public int StopLossLong { get => _stopLossLong.Value; set => _stopLossLong.Value = value; }
public int TakeProfitShort { get => _takeProfitShort.Value; set => _takeProfitShort.Value = value; }
public int StopLossShort { get => _stopLossShort.Value; set => _stopLossShort.Value = value; }
public int T1 { get => _t1.Value; set => _t1.Value = value; }
public int T2 { get => _t2.Value; set => _t2.Value = value; }
public int DeltaLong { get => _deltaLong.Value; set => _deltaLong.Value = value; }
public int DeltaShort { get => _deltaShort.Value; set => _deltaShort.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Twenty200ExpertAutoLotStrategy()
{
_takeProfitLong = Param(nameof(TakeProfitLong), 39)
.SetDisplay("TP Long (pips)", "Take profit for long", "Risk");
_stopLossLong = Param(nameof(StopLossLong), 147)
.SetDisplay("SL Long (pips)", "Stop loss for long", "Risk");
_takeProfitShort = Param(nameof(TakeProfitShort), 32)
.SetDisplay("TP Short (pips)", "Take profit for short", "Risk");
_stopLossShort = Param(nameof(StopLossShort), 267)
.SetDisplay("SL Short (pips)", "Stop loss for short", "Risk");
_t1 = Param(nameof(T1), 6)
.SetDisplay("T1", "First bar shift", "Logic");
_t2 = Param(nameof(T2), 2)
.SetDisplay("T2", "Second bar shift", "Logic");
_deltaLong = Param(nameof(DeltaLong), 1)
.SetDisplay("Delta Long", "Min rise in pips", "Logic");
_deltaShort = Param(nameof(DeltaShort), 1)
.SetDisplay("Delta Short", "Min fall in pips", "Logic");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_opens.Clear();
_stopPrice = 0m;
_takePrice = 0m;
_entryTime = default;
_isLong = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_opens.Clear();
_stopPrice = 0m;
_takePrice = 0m;
_entryTime = default;
_isLong = false;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_opens.Add(candle.OpenPrice);
var maxShift = Math.Max(T1, T2);
if (_opens.Count <= maxShift)
return;
var pip = Security?.PriceStep ?? 1m;
var openT1 = _opens[_opens.Count - 1 - T1];
var openT2 = _opens[_opens.Count - 1 - T2];
// Position management: check SL/TP
if (Position != 0)
{
if (_isLong)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
{
SellMarket();
return;
}
}
else
{
if (candle.HighPrice >= _stopPrice || candle.LowPrice <= _takePrice)
{
BuyMarket();
return;
}
}
return;
}
// Entry logic
var diffShort = openT1 - openT2;
var diffLong = openT2 - openT1;
if (diffShort > DeltaShort * pip && Position >= 0)
{
SellMarket();
_isLong = false;
_entryTime = candle.OpenTime;
_stopPrice = candle.OpenPrice + StopLossShort * pip;
_takePrice = candle.OpenPrice - TakeProfitShort * pip;
}
else if (diffLong > DeltaLong * pip && Position <= 0)
{
BuyMarket();
_isLong = true;
_entryTime = candle.OpenTime;
_stopPrice = candle.OpenPrice - StopLossLong * pip;
_takePrice = candle.OpenPrice + TakeProfitLong * pip;
}
}
}
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.Strategies import Strategy
class twenty_200_expert_auto_lot_strategy(Strategy):
"""Open price difference between two bar offsets with SL/TP management."""
def __init__(self):
super(twenty_200_expert_auto_lot_strategy, self).__init__()
self._tp_long = self.Param("TakeProfitLong", 39).SetDisplay("TP Long", "TP for long", "Risk")
self._sl_long = self.Param("StopLossLong", 147).SetDisplay("SL Long", "SL for long", "Risk")
self._tp_short = self.Param("TakeProfitShort", 32).SetDisplay("TP Short", "TP for short", "Risk")
self._sl_short = self.Param("StopLossShort", 267).SetDisplay("SL Short", "SL for short", "Risk")
self._t1 = self.Param("T1", 6).SetDisplay("T1", "First bar shift", "Logic")
self._t2 = self.Param("T2", 2).SetDisplay("T2", "Second bar shift", "Logic")
self._delta_long = self.Param("DeltaLong", 1).SetDisplay("Delta Long", "Min rise", "Logic")
self._delta_short = self.Param("DeltaShort", 1).SetDisplay("Delta Short", "Min fall", "Logic")
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(twenty_200_expert_auto_lot_strategy, self).OnReseted()
self._opens = []
self._stop_price = 0
self._take_price = 0
self._is_long = False
def OnStarted2(self, time):
super(twenty_200_expert_auto_lot_strategy, self).OnStarted2(time)
self._opens = []
self._stop_price = 0
self._take_price = 0
self._is_long = False
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle):
if candle.State != CandleStates.Finished:
return
self._opens.append(float(candle.OpenPrice))
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
pip = 1.0
max_shift = max(self._t1.Value, self._t2.Value)
if len(self._opens) <= max_shift:
return
# SL/TP check
if self.Position != 0:
if self._is_long:
if low <= self._stop_price or high >= self._take_price:
self.SellMarket()
self._stop_price = 0
self._take_price = 0
return
else:
if high >= self._stop_price or low <= self._take_price:
self.BuyMarket()
self._stop_price = 0
self._take_price = 0
return
return
open_t1 = self._opens[len(self._opens) - 1 - self._t1.Value]
open_t2 = self._opens[len(self._opens) - 1 - self._t2.Value]
diff_short = open_t1 - open_t2
diff_long = open_t2 - open_t1
if diff_short > self._delta_short.Value * pip and self.Position >= 0:
self.SellMarket()
self._is_long = False
self._stop_price = float(candle.OpenPrice) + self._sl_short.Value * pip
self._take_price = float(candle.OpenPrice) - self._tp_short.Value * pip
elif diff_long > self._delta_long.Value * pip and self.Position <= 0:
self.BuyMarket()
self._is_long = True
self._stop_price = float(candle.OpenPrice) - self._sl_long.Value * pip
self._take_price = float(candle.OpenPrice) + self._tp_long.Value * pip
def CreateClone(self):
return twenty_200_expert_auto_lot_strategy()