LINQ, Delegates e Eventos no Trading
Aula 5 de 7
Delegates — Callbacks
// Delegate personalizado
public delegate void TradeHandler(Trade trade);
public class TradeNotifier
{
private TradeHandler? _handlers;
public void Subscribe(TradeHandler handler)
=> _handlers += handler;
public void Unsubscribe(TradeHandler handler)
=> _handlers -= handler;
public void Notify(Trade trade)
=> _handlers?.Invoke(trade);
}
Events — Notificação Padrão
public class MatchingEngine
{
// Evento com EventHandler<T> padrão .NET
public event EventHandler<Trade>? TradeExecutado;
public event EventHandler<Ordem>? OrdemRejeitada;
public event EventHandler<MarketData>? BookAtualizado;
private void OnTradeExecutado(Trade trade)
{
TradeExecutado?.Invoke(this, trade);
}
public void ProcessarOrdem(Ordem ordem)
{
if (ordem.Quantidade <= 0)
{
OrdemRejeitada?.Invoke(this, ordem);
return;
}
// ... processamento ...
OnTradeExecutado(new Trade(/* ... */));
}
}
// Uso
engine.TradeExecutado += (sender, trade) =>
{
Console.WriteLine($"Trade: {trade.Quantidade} @ {trade.Preco}");
};
Func/Action — Delegates Genéricos
public class OrderValidator
{
// Func<entrada, retorno>
private readonly Func<Ordem, bool> _validateOrdem;
private readonly Func<Ordem, decimal?> _calcularTaxa;
// Action<entrada> — sem retorno
private readonly Action<Ordem> _onRejeicao;
public OrderValidator(
Func<Ordem, bool> validateOrdem,
Func<Ordem, decimal?> calcularTaxa,
Action<Ordem> onRejeicao)
{
_validateOrdem = validateOrdem;
_calcularTaxa = calcularTaxa;
_onRejeicao = onRejeicao;
}
public bool Validar(Ordem ordem)
{
if (!_validateOrdem(ordem))
{
_onRejeicao(ordem);
return false;
}
var taxa = _calcularTaxa(ordem);
return true;
}
}
LINQ — Análise de Dados
public class TradeAnalyzer
{
private readonly IEnumerable<Trade> _trades;
public TradeAnalyzer(IEnumerable<Trade> trades)
{
_trades = trades;
}
public IEnumerable<(string Simbolo, decimal Volume)> TopSimbolos(int n)
=> _trades
.GroupBy(t => t.Simbolo)
.Select(g => (Simbolo: g.Key,
Volume: g.Sum(t => t.Quantidade * t.Preco)))
.OrderByDescending(x => x.Volume)
.Take(n);
public decimal PrecoMedioPonderado(string simbolo)
=> _trades
.Where(t => t.Simbolo == simbolo)
.Aggregate(
(QtdTotal: 0m, ValorTotal: 0m),
(acc, t) => (
acc.QtdTotal + t.Quantidade,
acc.ValorTotal + t.Quantidade * t.Preco
),
acc => acc.QtdTotal > 0
? acc.ValorTotal / acc.QtdTotal
: 0m
);
public Dictionary<string, decimal> VolatilidadePorSimbolo()
=> _trades
.GroupBy(t => t.Simbolo)
.ToDictionary(
g => g.Key,
g => {
var precos = g.Select(t => t.Preco);
var media = precos.Average();
var variancia = precos
.Select(p => Math.Pow((double)(p - media), 2))
.Average();
return (decimal)Math.Sqrt(variancia);
});
}
LINQ em Tempo Real com MoreLINQ
// Janela deslizante de trades para VWAP
public class VwapCalculator
{
private readonly Queue<Trade> _janela = new();
private readonly int _tamanhoJanela;
public VwapCalculator(int tamanhoJanela = 100)
{
_tamanhoJanela = tamanhoJanela;
}
public decimal AdicionarTrade(Trade trade)
{
_janela.Enqueue(trade);
while (_janela.Count > _tamanhoJanela)
_janela.Dequeue();
return _janela.Sum(t => t.Quantidade * t.Preco)
/ _janela.Sum(t => t.Quantidade);
}
}
Eventos são o padrão de notificação no .NET. LINQ transforma consultas complexas em código declarativo. Use Func/Action para comportamentos injetáveis.