kb.erickguedes.com
C#: Matching Engine — Projeto Mercado Financeiro

OOP Aplicado a Mercado Financeiro

Aula 2 de 7

Classes — Modelagem de Ordem

public enum OrdemTipo
{
    LIMITE,
    MERCADO
}

public enum OrdemLado
{
    COMPRA,
    VENDA
}

public enum OrdemStatus
{
    PENDENTE,
    PARCIAL,
    PREENCHIDA,
    CANCELADA
}

public class Ordem
{
    public Guid Id { get; private set; }
    public string Simbolo { get; private set; }
    public OrdemLado Lado { get; private set; }
    public int Quantidade { get; private set; }
    public int QuantidadeRestante { get; private set; }
    public decimal? Preco { get; private set; }
    public OrdemTipo Tipo { get; private set; }
    public OrdemStatus Status { get; private set; }
    public DateTime CriadaEm { get; private set; }

    public Ordem(string simbolo, OrdemLado lado, int quantidade,
                 OrdemTipo tipo = OrdemTipo.LIMITE, decimal? preco = null)
    {
        Id = Guid.NewGuid();
        Simbolo = simbolo;
        Lado = lado;
        Quantidade = quantidade;
        QuantidadeRestante = quantidade;
        Tipo = tipo;
        Preco = tipo == OrdemTipo.LIMITE
            ? preco ?? throw new ArgumentException("Preço obrigatório para ordem limite")
            : null;
        Status = OrdemStatus.PENDENTE;
        CriadaEm = DateTime.UtcNow;
    }

    public bool PreencherParcial(int quantidade)
    {
        if (quantidade <= 0 || quantidade > QuantidadeRestante)
            return false;

        QuantidadeRestante -= quantidade;
        Status = QuantidadeRestante == 0
            ? OrdemStatus.PREENCHIDA
            : OrdemStatus.PARCIAL;
        return true;
    }

    public bool Cancelar()
    {
        if (Status == OrdemStatus.PREENCHIDA)
            return false;
        Status = OrdemStatus.CANCELADA;
        return true;
    }

    public override string ToString()
        => $"{Id}: {Lado} {Quantidade} {Simbolo} @ {(Preco?.ToString("F2") ?? "MERCADO")} [{Status}]";
}

Records — Imutabilidade

// Record — tipo por valor com imutabilidade
public record Trade(
    Guid Id,
    Guid OrdemCompraId,
    Guid OrdemVendaId,
    string Simbolo,
    int Quantidade,
    decimal Preco,
    DateTime ExecutadaEm
);

// Comportamento: value equality
var t1 = new Trade(Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(),
                   "AAPL", 100, 150.50m, DateTime.UtcNow);
var t2 = t1 with { Id = Guid.NewGuid() };  // cópia imutável

Interfaces e Injeção de Dependência

public interface IOrderBook
{
    void AdicionarOrdem(Ordem ordem);
    bool CancelarOrdem(Guid ordemId);
    IEnumerable<Trade> ExecutarMatches();
    OrdemBookSnapshot ObterSnapshot();
}

public interface IMarketDataProvider
{
    event Action<Trade> OnTrade;
    decimal ObterUltimoPreco(string simbolo);
}

Record Struct — Performance

// Record struct (C# 10+) — baixo overhead
public readonly record struct PrecoNivel(decimal Preco, int QuantidadeTotal);

public class OrderBook
{
    private readonly SortedDictionary<decimal, int> _compras = new();  // bid
    private readonly SortedDictionary<decimal, int> _vendas = new();   // ask

    public IEnumerable<PrecoNivel> Bids
        => _compras.Select(kv => new PrecoNivel(kv.Key, kv.Value));

    public IEnumerable<PrecoNivel> Asks
        => _vendas.Select(kv => new PrecoNivel(kv.Key, kv.Value));
}

C# moderno tem records para imutabilidade e value equality. No mercado financeiro, imutabilidade é crucial para integridade de dados de negociação.