Sprint 5 : Modifying the classes architecture

To end the month of June, some modification has been made on the classes and layers. Once again, it is to simplify the maintenance. The biggest change is in the business layer. Previously, some classes were present but should not be. It is the same in the Data Access Layer which had some classes about Email. Yes, it is the place to send email but not to store those classes. Now, the Business Layer has all entities and non-entities classes like Email.

The second big change in the Sprint 5 was about the introduction of Trading business logic entities like Order, Portfolio, Stock and Transaction.

The Order class is abstract and has several class the inherit it like the StockOrder. The StockOrder class is very simple and add only the StockSymbol. It inherits from all other properties.

public class StockOrder : Order
{
    [Required]
    public string StockSymbol { get; set; }
        
    public override IEnumerable<ValidationResult> ValidateChildren()
    {
        return base.ValidateChildren();
    }
}

The Order class is interesting for several reasons. First, it uses Value Object design pattern with the collaboration of Entity Framework. Not only it use Value Object but it does use it in three different ways. The first one is with TransactionType. It uses the pattern of having the TransactionTypeId directly into the classes to let Entity Framework save this one without having to attach the whole value object. This also has a performance gain by having the value object class without requiring to include. This is possible with the GetFromId method defined in the base class of the value object. The second way is with the OrderType. This time, it does not require to save anything in the database since it is calculated on the fly by the property getter. The last way value object is used is hidden inside the complex type Money. This one use value object for the currency type but cannot be set with a foreign key since Complex Type cannot have foreign key to any table. The integrity is only done on the code side.

public abstract class Order : Implementations.Model
{
    protected Order()
    {
        this.Status = OrderStatusType.Waiting;
    }
 
    [Required]
    public int Quantity { get; set; }
 
 
    public int TransactionTypeId
    {
        get { return TransactionType.Id; }
        set { this.TransactionType = TransactionType.GetFromId(value); }
    }
    [Required]
    public TransactionType TransactionType { get; set; }
 
 
    public OrderType OrderType
    {
        get
        {
 
            if (PriceStop != null && PriceLimit != null)
                return OrderType.StopLimit;
            if (PriceStop == null && PriceLimit != null)
                return OrderType.Limit;
            return OrderType.Market;
        }
        set { }/*This is required for Entity Framework*/
    }
 
    public Money PriceLimit { get; set; }
 
    public Money PriceStop { get; set; }
 
    [Required]
    public DateTime PlacedOrderTime { get; set; }
 
    [Required]
    public DateTime ExpirationOrderTime { get; set; }
 
    public bool IsMarketPriceOrder
    {
        get { return PriceLimit == null && PriceStop == null; }
    }
 
    public Portefolio Portefolio { get; set; }
    public int PortefolioId { get; set; }
 
    public ApplicationUser UserWhoPlacedTheOrder { get; set; }
    public string UserWhoPlacedTheOrderId { get; set; }
 
    public int StatusId
    {
        get { return Status.Id; }
        set { this.Status = OrderStatusType.GetFromId(value); }
    }
 
    public OrderStatusType Status { get; set; }
 
    public override IEnumerable<ValidationResult> ValidateChildren()
    {
        if (!this.IsMarketPriceOrder)
        {
            if (this.PriceStop != null)
            {
                if (TransactionType == TransactionType.Buy)
                {
                    if (PriceLimit < PriceStop)
                    {
                        yield return new ValidationResult("Price Limit must be higher or equal to the price stop"
                            , new[] { LambdaHelper.GetPropertyName<Order>(d => d.PriceLimit), LambdaHelper.GetPropertyName<Order>(d => d.PriceStop)} );
                    }
                }
                else if (TransactionType == TransactionType.Sell)
                {
                    if (PriceLimit > PriceStop)
                    {
                        yield return new ValidationResult("Price Limit must be lower or equal to the price stop"
                            , new[] { LambdaHelper.GetPropertyName<Order>(d => d.PriceLimit), LambdaHelper.GetPropertyName<Order>(d => d.PriceStop) });
                    }
                }
            }
        }
    }
 
    public IEnumerable<ValidationResult> ValidateNewOrder(IRunningContext runningContext, int numberDayMaximumForExpirationOrder)
    {
        if (this.ExpirationOrderTime.Subtract(runningContext.GetCurrentTime()).TotalDays > numberDayMaximumForExpirationOrder)
            yield return new ValidationResult(string.Format("You cannot set an order with a ending time above {0}", numberDayMaximumForExpirationOrder)
                                            , new[] { LambdaHelper.GetPropertyName<Order>(d => d.ExpirationOrderTime) });
    }
}

The Order class is also interesting because it add some business logic like the validation of a new order that can be called when the order is created. This is used by the new class Portfolio. The Portfolio class is used in the OrderService class when we record a new order into a portfolio. The order is pass to the portfolio to be added, and this one validate if it is possible to add. A lot of business logic is done here to know if the order is fine or not. The Order Service looks so far like that for the validation:

public IEnumerable<ValidationResult> RecordOrder(StockOrder order)
{
    var validationsToReturn = new List<ValidationResult>();
 
    //1- Current contest from the portefolio
    //2- Verify that the contest can execute this order (validations for contest/order)
    var portefolio = this.portefolioAccessor.GetById(order.PortefolioId);
    IEnumerable<ValidationResult> validationContests = portefolio.ValidateOrder(order, this.runningContext, this.quoteProvider);
    if (validationContests.Any())
    {
        return validationContests;
    }
 
    //3- Validate the order
    var validations = order.Validate();
    if (validations.Any())
    {
        return validationsToReturn;
    }
 
    //4- Record the order in the order queue to be executed at the proper time
     
    var validationsOnSave = this.orderAccessor.RecordOrder(order);
    validationsToReturn = validationsToReturn.Concat(validationsOnSave).ToList();
     
    //5- Display any feedback from the RecordOrder operation
    return validationsToReturn;
}

The interesting part is the one the validate the order from the portfolio. The code below is not yet done but it shows that some validation are done. At some point, the validation does not concern the portfolio rules but the order. This is why this method call the Order.ValidateNewOrder.

public IEnumerable<ValidationResult> ValidateOrder(StockOrder order, IRunningContext runningContext, IQuoteProvider quoteProvider)
{
    if (!this.Contest.ContestOrderType.Accept(order.OrderType))
        yield return new ValidationResult("Order is not valid for the current contest", new[]{LambdaHelper.GetPropertyName<StockOrder>(d=>d.OrderType)});
     
    if((order.OrderType == OrderType.Limit || order.OrderType == OrderType.StopLimit) && this.NumberOfActiveOrder>=this.Contest.TransactionRules.MaximumLimitOrderSameTime)
        yield return new ValidationResult("The maximum number of order has been reached.", new[] { LambdaHelper.GetPropertyName<Portefolio>(d => d.NumberOfActiveOrder) });
 
    var numberDayMaximumForExpirationOrder = 7;//ToDo
    var orderValidations = order.ValidateNewOrder(runningContext, numberDayMaximumForExpirationOrder);
    foreach (var validationResult in orderValidations)
    {
        yield return validationResult;
    }
 
    if (!this.Contest.TransactionRules.IsInOrderTimeFrame(runningContext.GetCurrentTime()))
    {
        yield return new ValidationResult(string.Format("Order must be set between {0} and {1}"
                                                , this.Contest.TransactionRules.OrderStartingTime
                                                , this.Contest.TransactionRules.OrderEndingTime)
                                                , new[] {LambdaHelper.GetPropertyName<Portefolio>(d => d.Contest.TransactionRules)});
    }
    var stockValidations = quoteProvider.GetValidation().Validate(order.StockSymbol);
    foreach (var validationResult in stockValidations)
    {
        var newValidationWithMembers = new ValidationResult(validationResult.ErrorMessage, new[] {LambdaHelper.GetPropertyName<StockOrder>(d => d.StockSymbol)});
        yield return newValidationWithMembers;
    }
}

Not only it calls the Order validation but it also validate the Stock Symbol. This is interesting because it use the QuoteProvider. This allow us to change the stock provider from any provider like Yahoo to Google without having to change a lot of logic. It implements the strategy pattern.

Additional information about the Strategy Pattern and the Quote Provider will be provided in a later article.

More about Patrick Desjardins

Leave a Reply

Your email address will not be published. Required fields are marked *