admin管理员组

文章数量:1516870

I'm working on a cryptocurrency grid trading system where bots create Order entities. When an Order is created, it triggers a domain event to send the order to the corresponding Exchange. The issue is that Order does not have direct access to Exchange, making it unclear how to properly trigger the event.

// Order.cs
public void CreateOrderPlacedEvent()
{
    AddDomainEvent(new OrderPlacedEvent(Bot.Exchange.Name)); // <- this part here. It's null atm.
    // The event needs to know which exchange to forward the order to.
}

Issue:

  • The Order class does not have a direct reference to the Exchange entity, but the domain event needs to know which Exchange to send the order to.
  • I'm considering adding ExchangeId to the Order entity, but I'm concerned this might create a circular reference since the Bot already references Exchange.

Question:

How can I properly trigger the domain event to send the order to the correct Exchange without introducing circular dependencies between Order, Bot, and Exchange?

Data Model:

public class Bot : BaseAuditableEntity
{
    // EF Core cannot bind value object in EF constructor: 
    [UsedImplicitly]
    private Bot() { }
    
    public Bot(Guid userId, Guid exchangeId, Pair pair, decimal investment)
    {
        Id = Guid.CreateVersion7();
        UserId = userId;
        ExchangeId = exchangeId;
        Pair = pair;
        Investment = investment;
    }
    
    public Guid UserId { get; private set; }
    public Guid ExchangeId { get; private set; }
    public Pair Pair { get; private set; } = null!;
    public decimal Investment { get; private set; }
    
    public User User { get; private set; } = null!;
    public Exchange Exchange { get; private set; } = null!;
}

public class Exchange : BaseAuditableEntity
{
    public Exchange(string name)
    {
        Id = Guid.CreateVersion7();
        Name = name;
        IsActive = true;
    }

    public string Name { get; private set; }
    public bool IsActive { get; private set; }

    public void Activate()
    {
        IsActive = true;
    }

    public void Deactivate()
    {
        IsActive = false;
    }
}

public class Order : BaseAuditableEntity
{
    // EF Core cannot bind value object in EF constructor: 
    [UsedImplicitly]
    private Order() { }
    
    public Order(Guid botId, Pair pair, OrderSide side, decimal quantity, decimal price, string? clientOrderId = null)
    {
        Id = Guid.CreateVersion7();
        BotId = botId;
        Pair = pair;
        Side = side;
        Status = new OrderState(OrderStatus.New);
        Quantity = quantity;
        Price = price;
        ClientOrderId = clientOrderId;
        CreateOrderPlacedEvent();
    }
    
    public Guid BotId { get; private set; }
    public Pair Pair { get; private set; } = null!;
    public OrderSide Side { get; private set; }
    public OrderState Status { get; private set; } = null!;
    public decimal Quantity { get; private set; } // TODO: + for buy; - for sell ??
    public decimal Price { get; private set; }
    public string? ClientOrderId { get; private set; }

    public Bot Bot { get; private set; } = null!;
    
    // TODO: If we have ExchangeId here, will it cause a circular loop because a Bot relates to Exchange?
    
    public void Cancel()
    {
        AddDomainEvent(new OrderCanceledEvent());
        Status = Status.Cancel();
    }

    public void CreateOrderPlacedEvent()
    {
        AddDomainEvent(new OrderPlacedEvent(Bot.Exchange.Name));
    }
}

public class User : BaseAuditableEntity
{
    public User(string email, string password)
    {
        Id = Guid.CreateVersion7();
        Email = email;
        Password = password;
    }

    public string Email { get; private set; }
    public string Password { get; private set; }

    public ICollection<UserExchange> UserExchanges { get; } = new List<UserExchange>();
    public ICollection<VirtualBalance> VirtualBalances { get; } = new List<VirtualBalance>();
}

public class UserExchange
{
    public UserExchange(Guid userId, Guid exchangeId, string apiKey, string secretKey, string? passphrase = null)
    {
        UserId = userId;
        ExchangeId = exchangeId;
        ApiKey = apiKey;
        SecretKey = secretKey;
        Passphrase = passphrase;
    }

    public Guid UserId { get; private set; }
    public Guid ExchangeId { get; private set; }
    public string ApiKey { get; private set; }
    public string SecretKey { get; private set; }
    public string? Passphrase { get; private set; }
    
    public User User { get; private set; } = null!;
    public Exchange Exchange { get; private set; } = null!;
}

public class VirtualBalance : BaseAuditableEntity
{
    public VirtualBalance(string asset, decimal available, decimal locked)
    {
        Id = Guid.CreateVersion7();
        Asset = asset;
        Available = available;
        Locked = locked;
    }

    public string Asset { get; private set; }
    public decimal Available { get; private set; }
    public decimal Locked { get; private set; }
    
    public Guid UserId { get; private set; }
    public User User { get; private set; } = null!;
}

本文标签: