Эта стратегия воспроизводит логику советника MetaTrader «eKeyboardTrader», используя высокоуровневый API StockSharp. В оригинале торговля выполнялась через горячие клавиши и текстовые подсказки на графике. В версии для StockSharp взаимодействие перенесено в параметры стратегии, при этом последовательность ручных действий, проверки безопасности и настройка защитных ордеров сохранены.
Торговая логика
Подписка на Level1 — стратегия подписывается на поток лучших бид/аск котировок и использует их для проверки готовности к исполнению ручных команд.
Ручные команды — три булевых параметра (BuyRequest, SellRequest, CloseRequest) заменяют сочетания клавиш B, S и C. При установке значения true выполняется соответствующая рыночная операция, после чего флаг автоматически сбрасывается.
Ограничение частоты — между командами действует пауза в одну секунду, что защищает от повторной отправки, как и в оригинальном советнике.
Защита позиций — расстояния до стоп-лосса и тейк-профита задаются в пунктах MetaTrader и переводятся в абсолютные цены через Security.PriceStep. При наличии хотя бы одного защитного расстояния включается StartProtection, благодаря чему каждая сделка сопровождается выставлением защитных заявок.
Учёт проскальзывания — параметр SlippagePoints сохранён для совместимости и выводится в лог при каждой ручной сделке, аналогично комментариям советника.
Параметры
Параметр
Описание
OrderVolume
Базовый объём для ручных рыночных заявок.
StopLossPoints
Дистанция до защитного стоп-лосса в пунктах MetaTrader (0 — отключено).
TakeProfitPoints
Дистанция до защитного тейк-профита в пунктах MetaTrader (0 — отключено).
SlippagePoints
Информационный допуск по проскальзыванию, выводимый в лог.
BuyRequest
Установите true, чтобы отправить рыночную покупку (с последующим сбросом).
SellRequest
Установите true, чтобы отправить рыночную продажу (с последующим сбросом).
CloseRequest
Установите true, чтобы закрыть нетто-позицию по рынку (с последующим сбросом).
Отличия от версии MQL
На графике нет текстовых подсказок и звуковых сигналов — информацию о действиях можно отслеживать через лог.
Защитные заявки управляются через StartProtection, который закрывает позицию рыночными ордерами при достижении порога, вместо модификации отдельных тикетов.
Горячие клавиши заменены параметрами. Интерфейс, размещающий стратегию, может привязать к ним любые элементы управления.
Диагностика торговых запросов в MetaTrader сведена к лаконичным сообщениям в журнале.
Рекомендации по использованию
Перед стартом стратегии обязательно назначьте Security и Portfolio, как это требует исходный советник.
Проверка флагов выполняется при поступлении новых данных Level1, поэтому в спокойном рынке исполнение произойдёт на ближайшей котировке.
Изменение StopLossPoints или TakeProfitPoints во время работы потребует перезапуска стратегии, чтобы переинициализировать модуль защиты.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// eKeyboard Trader strategy: CCI trend following.
/// Buys when CCI crosses above +100, sells when CCI crosses below -100.
/// </summary>
public class EKeyboardTraderStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private decimal _prevCci;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public EKeyboardTraderStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal cci)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevCci <= 100 && cci > 100 && Position <= 0) BuyMarket();
else if (_prevCci >= -100 && cci < -100 && Position >= 0) SellMarket();
}
_prevCci = cci;
_hasPrev = 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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class e_keyboard_trader_strategy(Strategy):
"""
eKeyboard Trader strategy: CCI trend following.
Buys when CCI crosses above +100, sells when CCI crosses below -100.
"""
def __init__(self):
super(e_keyboard_trader_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._cci_period = self.Param("CciPeriod", 14) \
.SetDisplay("CCI Period", "CCI period", "Indicators")
self._prev_cci = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(e_keyboard_trader_strategy, self).OnReseted()
self._prev_cci = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(e_keyboard_trader_strategy, self).OnStarted2(time)
self._has_prev = False
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(cci, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, cci)
self.DrawOwnTrades(area)
def _process_candle(self, candle, cci_val):
if candle.State != CandleStates.Finished:
return
cci_val = float(cci_val)
if self._has_prev:
if self._prev_cci <= 100.0 and cci_val > 100.0 and self.Position <= 0:
self.BuyMarket()
elif self._prev_cci >= -100.0 and cci_val < -100.0 and self.Position >= 0:
self.SellMarket()
self._prev_cci = cci_val
self._has_prev = True
def CreateClone(self):
return e_keyboard_trader_strategy()