A Estratégia de Lista de Posições reproduz o comportamento do script original do MetaTrader ao imprimir periodicamente as posições atuais do portfólio no log da estratégia. É um helper de monitoramento exclusivo que nunca coloca ordens. Em vez disso, constrói um snapshot das posições abertas para que o operador possa inspecionar símbolo, direção, tamanho, preço de entrada e lucro atual diretamente do Designer ou dos logs do StockSharp.
Recursos principais
Relatório de posições orientado por temporizador com o primeiro snapshot entregue imediatamente após o início da estratégia.
Filtragem opcional pelo ativo da estratégia ou por identificador de estratégia (o análogo do número mágico do MetaTrader).
Saída de log detalhada incluindo o identificador de posição, último tempo de mudança, lado, quantidade, preço médio e lucro.
Processamento thread-safe que evita sobreposições de callbacks do temporizador quando o ambiente está ocupado.
Parâmetros
Nome
Descrição
Padrão
StrategyIdFilter
Identificador de estratégia a pular. Quando deixado vazio, todas as posições são reportadas.
String vazia
SelectionMode
Controla se posições de cada símbolo ou apenas de Strategy.Security são reportadas.
AllSymbols
TimerInterval
Intervalo entre snapshots consecutivos de posições.
6 segundos
Como funciona
Durante OnStarted, a estratégia verifica que um portfólio está anexado e que o intervalo do temporizador é positivo.
Um System.Threading.Timer é criado com zero de atraso para que o primeiro relatório seja produzido imediatamente e depois repetido no intervalo configurado.
Cada tick do temporizador chama ProcessPositions, que itera sobre Portfolio.Positions, aplica os filtros opcionais de símbolo e identificador de estratégia, e acrescenta linhas formatadas a um StringBuilder.
Quando pelo menos uma posição passa os filtros, a tabela montada é escrita no log com LogInfo. Se nada corresponder, uma notificação concisa é registrada em vez disso.
As sobreposições do temporizador são evitadas com um guarda interlocked para que a I/O lenta não possa acionar execuções concorrentes.
Notas de uso
Atribua tanto Portfolio quanto Connector antes de iniciar a estratégia. Se SelectionMode estiver configurado como CurrentSymbol, também configure Strategy.Security para o instrumento que deseja monitorar.
Para emular o filtro magic do MetaTrader, preencha StrategyIdFilter com o valor de string usado como StrategyId quando outras estratégias enviam ordens. Essas posições serão excluídas do relatório.
A estratégia nunca modifica posições ou registra ordens, tornando-a segura para executar ao lado de lógica de trading ao vivo como um widget informacional.
A saída do log é agrupada sob o cabeçalho de coluna Idx | Symbol | PositionId | LastChange | Side | Quantity | AvgPrice | PnL para que possa ser facilmente analisado por ferramentas externas, se necessário.
Diferenças em relação à versão MQL
O MetaTrader usa um número magic de 64 bits sem sinal. As posições do StockSharp expõem o identificador de estratégia como uma string, portanto o filtro aceita valores textuais.
Em vez de escrever no comentário do gráfico, esta portagem registra o snapshot via LogInfo, que é visível no Designer, Runner ou qualquer listener de log.
A versão do StockSharp protege contra invocações sobrepostas do temporizador para permanecer responsiva sob carga pesada.
Os timestamps dependem de Position.LastChangeTime, que reflete as atualizações de posição do StockSharp, enquanto o script MQL exibia o tempo de criação do ticket.
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>
/// Logs the current position on every candle. Simplified from the original multi-position listing.
/// When position changes direction based on candle close, trades accordingly.
/// </summary>
public class ListPositionsStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _logInterval;
private int _candleCount;
private decimal? _prevClose;
/// <summary>
/// Candle type for monitoring.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Number of candles between position log entries.
/// </summary>
public int LogInterval
{
get => _logInterval.Value;
set => _logInterval.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public ListPositionsStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe for monitoring", "General");
_logInterval = Param(nameof(LogInterval), 10)
.SetGreaterThanZero()
.SetDisplay("Log Interval", "Log position every N candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candleCount = 0;
_prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType)
.Bind(ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormed)
return;
_candleCount++;
if (_prevClose != null)
{
if (candle.ClosePrice > _prevClose.Value && Position <= 0)
BuyMarket();
else if (candle.ClosePrice < _prevClose.Value && Position >= 0)
SellMarket();
}
if (_candleCount % LogInterval == 0)
{
LogInfo($"Position: {Position}, Price: {candle.ClosePrice:0.#####}, Equity: {Portfolio?.CurrentValue:0.##}");
}
_prevClose = candle.ClosePrice;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class list_positions_strategy(Strategy):
def __init__(self):
super(list_positions_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._log_interval = self.Param("LogInterval", 10)
self._candle_count = 0
self._prev_close = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def LogInterval(self):
return self._log_interval.Value
@LogInterval.setter
def LogInterval(self, value):
self._log_interval.Value = value
def OnStarted2(self, time):
super(list_positions_strategy, self).OnStarted2(time)
self._candle_count = 0
self._prev_close = None
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
if not self.IsFormed:
return
close = float(candle.ClosePrice)
self._candle_count += 1
if self._prev_close is not None:
if close > self._prev_close and self.Position <= 0:
self.BuyMarket()
elif close < self._prev_close and self.Position >= 0:
self.SellMarket()
self._prev_close = close
def OnReseted(self):
super(list_positions_strategy, self).OnReseted()
self._candle_count = 0
self._prev_close = None
def CreateClone(self):
return list_positions_strategy()