Estratégia de painel utilitário leve de negociação manual
Visão geral
A Estratégia do painel utilitário leve de negociação manual replica o comportamento do painel MT4 "Utilitário leve de negociação manual" usando a estratégia de alto nível StockSharp API. Ele expõe os mesmos controles interativos que os parâmetros de estratégia para que o operador possa alternar entre ordens de mercado, limite e stop, ajustar o cálculo automático de preços, configurar o gerenciamento de volume e anexar controles de risco sem depender de objetos gráficos personalizados.
A estratégia é projetada para negociação discricionária. Os pedidos são acionados manualmente alterando os parâmetros Send Buy Order ou Send Sell Order na IU. Cada comando é reconhecido imediatamente, enquanto a estratégia mantém todos os cálculos — como sugestões automáticas de preços e níveis de risco — sincronizados com dados de mercado em tempo real.
Principais recursos
Envio manual de pedidos para compradores e vendedores, com suporte para ordens de mercado, limite e stop.
Sugestão automática de preço que reflete a lógica do painel MT4, atualizando o limite proposto ou o preço stop do último fluxo de compra/venda.
Modo de preço manual opcional que permite ao operador digitar o nível de disparo desejado respeitando os tamanhos dos passos do instrumento.
Gerenciamento de volume com tamanho de lote global e volumes de compra/venda individuais quando a chave de controle de lote está habilitada.
Gerenciamento integrado de stop-loss e take-profit implementado na camada de estratégia para emular proteções anexadas a pedidos no MT4.
Feedback detalhado por meio de parâmetros que sempre refletem os últimos níveis de entrada calculados para ambos os lados.
Notas de conversão
Os objetos gráficos MT4 (botões, rótulos e caixas de edição) são substituídos por parâmetros de estratégia agrupados em seções lógicas para fácil acesso no Hydra/Terminal.
As paradas e metas de proteção são tratadas internamente, observando o preço de mercado ao vivo porque StockSharp não os incorpora em ordens pendentes da mesma forma que o MT4.
As compensações de preços expressas em pontos reutilizam os metadados do instrumento (PriceStep e VolumeStep) para que os limites e paradas sempre respeitem as restrições cambiais.
Uso
Anexe a estratégia a um título e portfólio no Hydra ou Terminal.
Configure o tamanho do lote padrão, parâmetros de risco e compensações de preço.
Opcionalmente, habilite Lot Control para manter volumes independentes para os botões de compra e venda.
Escolha o tipo de ordem (mercado, limite pendente ou stop pendente) e se o preço de gatilho deve seguir o mercado ou permanecer manual.
Quando estiver pronto, alterne Send Buy Order ou Send Sell Order para true. A estratégia enviará o pedido correspondente e redefinirá o sinalizador para false depois de processado.
O gestor de proteção fechará as posições abertas nos níveis de stop-loss ou take-profit configurados, calculados a partir do preço de entrada executado.
Arquivos
CS/ManualTradingLightweightUtilityPanelStrategy.cs – Implementação da estratégia em C#.
README.md – Documentação em inglês (este arquivo).
README_zh.md – Documentação em chinês simplificado.
README_ru.md – Documentação russa.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Manual Trading Panel strategy: SMA mean reversion with RSI filter.
/// Buys when close is below SMA and RSI is oversold, sells when above and overbought.
/// </summary>
public class ManualTradingLightweightUtilityPanelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _signalCooldownCandles;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public ManualTradingLightweightUtilityPanelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_smaPeriod = Param(nameof(SmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA period", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 8)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candlesSinceTrade = SignalCooldownCandles;
var sma = new SimpleMovingAverage { Length = SmaPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(sma, rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal sma, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
var close = candle.ClosePrice;
if (close < sma && rsi < 35 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (close > sma && rsi > 65 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 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 SimpleMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class manual_trading_lightweight_utility_panel_strategy(Strategy):
def __init__(self):
super(manual_trading_lightweight_utility_panel_strategy, self).__init__()
self._sma_period = self.Param("SmaPeriod", 20) \
.SetDisplay("SMA Period", "SMA period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._signal_cooldown = self.Param("SignalCooldownCandles", 8) \
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading")
self._sma = None
self._rsi = None
self._candles_since_trade = 0
@property
def sma_period(self):
return self._sma_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def signal_cooldown(self):
return self._signal_cooldown.Value
def OnReseted(self):
super(manual_trading_lightweight_utility_panel_strategy, self).OnReseted()
self._sma = None
self._rsi = None
self._candles_since_trade = self.signal_cooldown
def OnStarted2(self, time):
super(manual_trading_lightweight_utility_panel_strategy, self).OnStarted2(time)
self._sma = SimpleMovingAverage()
self._sma.Length = self.sma_period
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
self._candles_since_trade = self.signal_cooldown
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._sma, self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, sma_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._sma.IsFormed or not self._rsi.IsFormed:
return
if self._candles_since_trade < self.signal_cooldown:
self._candles_since_trade += 1
close = float(candle.ClosePrice)
sma_val = float(sma_value)
rsi_val = float(rsi_value)
if close < sma_val and rsi_val < 35.0 and self.Position <= 0 and self._candles_since_trade >= self.signal_cooldown:
self.BuyMarket()
self._candles_since_trade = 0
elif close > sma_val and rsi_val > 65.0 and self.Position >= 0 and self._candles_since_trade >= self.signal_cooldown:
self.SellMarket()
self._candles_since_trade = 0
def CreateClone(self):
return manual_trading_lightweight_utility_panel_strategy()