Super Simple Stock Market (SSSM) is an object-oriented system designed to run trading in a fictitious Global Beverage Corporation Exchange stock market. Besides recording trades for common and preferred stock, SSSM is able to calculate both stock specific metrics (such as Dividend Yield and P/E Ratio) and index metrics (such as Volume Weighted Stock Price and a GBCE specific All Share Index).
- Prices will be given in a single unspecified currency with 100 subunits
- Minimum stock price is 0.01
- Minimum fixed dividend is 1%
- No fractional shares
- P/E Ratio is based on past performance (i.e., on last dividend paid)
- Timestamps are given in machine time (i.e.,
Instant
); the system is not timezone aware - Trades represent committed orders and all prices are final
- Trades will not be evicted from history (i.e., history can contain trades older than 5 minutes)
- Trades are written to the history more often than metrics are computed (i.e., system is optimized for writes)
- Since no trades are evicted and data is held in memory the system will not be submitted to unreasonable load
- SSSM is a single threaded system
Stocks and Trades are immutable by design. The system at this stage is not multithreaded but immutability comes with highly desirable characteristics such as side effect free programming and simple reasoning about the code.
Mutable collections are still used sparingly and isolated (e.g., for trades history).
Preferred and common stocks are types of stock (IS-A relationship). Fixed dividend is exclusive to preferred stocks and
dividend yield is dependent on the stock type. It would be possible to design the model relying in a type discriminator
(e.g, StockType
enum). A mix of composition and delegation could be used to model dynamic swappable behaviour. In the
lack of such requirements, inheritance seems like a natural way to design the model respecting SOLID
Open/Closed principle. Special care is taken to follow the Liskov Substitution Principle, plus encapsulation
and patterns such as static factory methods are used to hide implementation details from the API.
On the other end of the spectrum, it would not make much sense to apply inheritance for different types of Trade
since
in SSSM all trades behave the same. A TradeIndicator
enum discriminator is used instead.
In accordance with Domain-driven design practices a StockMarketService
class provides the required methods for
calculating Volume Weighted Stock price and the GBCE specific All Share Index.
The data itself is written and retrieved using an in-memory implementation of StockRepository
. Internally, a
MultiMap stores trades for each kind of stock.
Finally, a geometric mean summary Collector
is implemented as an alternative for a private or public static utility
method in order to comply with the Simple responsibility principle.
Decimal values are represented with BigDecimal instead of types like double
and long
.
- Internal computations use a precision of 30 digits
- The fractional part of monetary values are scaled to the second digit
- The fractional part of percentage values are scaled to the fifth digit
ROUND_HALF_EVEN
policy is used for rounding.
It is certainly possible to design a production quality toy project. On the other hand, it is hard to ignore that a large enterprise project may call for a different toolset than a self-contained exercise.
Tools such as Spring Boot are able to bootstrap a production grade application with all the bells and whistles in a matter of minutes. Still, I feel that overengineering a toy project to emulate enterprise architecture defeats the purpose of the exercise. Thus, while I'm fully aware of the benefits that IoC containers, a bean validation framework etc could bring to the project, I've chosen to stick with a basic clean design.
This does not mean ignoring tools altogether:
- Lombok is used to reduce boilerplate code
- Guava brings that extra level of expressiveness with custom collections, preconditions etc to the project.
- SLF4J is used as lightweight logging facade loosely coupled to a
java.util.logging
implementation.
A suite of TestNG unit tests with AssertJ assertions is provided. Surefire reports can be generated with:
mvn test
While Spock was initially considered, this project is still too small and a complex BDD framework would be an overkill. For the same reason, automatic coverage, load and acceptance tests were not implemented for this version of the software.
In order to build the project Maven 3 and Oracle JDK 8 are required. The project can be built with:
mvn clean install
Super Simple Stock Market itself is IDE agnostic. Some IDEs may require extra configuration in order to play well with Lombok.