In our very first demo series, we showcase a dynamic aspect of Calculation Engine (A Premium Rating Engine) that adapts effortlessly to new requirements. The demo highlights how you can extend the engine with new premium factors, like AQI and Trekkie without changing the Calculation Engine’s code. Instead, the flexible design allows it to incorporate new premium factors simply by updating Premium Factors and Formulas in MongoDB database.
The demo walks through a series of steps that illustrate the engine's dynamic behavior. Here’s a breakdown of the demo:
Starting the Service:
The Calculation Service is containerized. First step is launching the docker and once the container is up and running, we are starting the service application.
> docker compose up
> dotnet run --environment=Development
This service is responsible for calculating premiums based on various factors and formulas. It initializes by loading static references, premium factors, and formulas from pre-configured data.
Run Tests via Swagger:
With the service running, we execute a series of tests using Swagger. These tests validate the core functionality of the rating engine by ensuring that existing formulas are working as expected.
Add New Premium Factor – AQI:
One of the demo’s highlights is the seamless integration of a new premium factors, and creating a new formula to use the new premium factor. We are using AQI (Air Quality Index) to demonstrate the dynamic nature of Calculation Engine.
Note: The required data is added to MongoDB using a script.
// Switch to the static reference database
use("hls-staticreferencedb");
// Creating static list for air quality indexes
db.createCollection("air-quality-indexes");
const createAirQualityIndexes = [
{ "type": "Good" },
{ "type": "Moderate" },
{ "type": "Unhealthy for Sensitive Groups" },
{ "type": "Unhealthy" },
{ "type": "Very Unhealthy" },
{ "type": "Hazardous" }
];
const createAirQualityIndexesWithId = createAirQualityIndexes.map((aqi, index) => {
return {
air_quality_index_id: "AQI-" + String(index + 1).padStart(3, '0'),
type: aqi.type,
status: "Active",
display_order: index + 1,
version: 1,
effective_date: new Date(),
replaced_date: null
};
});
db["air-quality-indexes"].insertMany(createAirQualityIndexesWithId);
// Retrieve the AQI list from the "air-quality-indexes" collection
const airQualityIndexesList = db["air-quality-indexes"].find({}).toArray();
// Switch to the calculation database
use("hls-calculationdb");
// Set categoryIdCount to 12 as required, since we have 11 categories before this
let categoryIdCount = 12;
// Helper function to generate a random weight between 0.05 and 0.5
function getRandomWeight() {
return (Math.random() * (0.5 - 0.05) + 0.05).toFixed(3);
}
// Function to generate an additive adjustment percentage (0 to 4)
function getAddToAdjustment() {
return parseFloat((Math.random() * 4).toFixed(3));
}
// Function to generate a discount adjustment percentage (-5 to 0)
function getDiscountAdjustment() {
return parseFloat((Math.random() * -5).toFixed(3));
}
// Insert a new premium factor document for Air Quality using the AQI list
db["premium-factors"].insertOne({
category_id: String(categoryIdCount).padStart(4, '0'),
category: "AirQuality",
weight: parseFloat(getRandomWeight()),
factors: airQualityIndexesList.map((aqi, index) => ({
factor_name: aqi.type,
adjustment_percentage: index === 0 ? getDiscountAdjustment() : getAddToAdjustment()
})),
status: "Active",
version: 1,
effective_date: new Date(),
replaced_date: null,
scheduled_replacement_date: null
});
// Switch to the calculation database (if not already there)
use("hls-calculationdb");
// Insert a new formula document that uses the Air Quality factor
db["premium-formulas"].insertOne({
formula_name: "Base Premium With Air Quality Adjustment",
formula_id: "Base-010",
description: "Calculates the base premium based on base rate with Air Quality index premium factors.",
expression_text: "base_rate * (1 + Gender + NicotineUse + AirQuality)"
});
Restart the Service and run AQI Test:
In a real-world scenario, the Calculation Engine’s data is stored in a service cache that refreshes nightly. To load the new formulas, we restart the service. With the service running again, the AQI test confirms that AQI is now a functional part of the premium calculation.
Introduce a different type of factor – Trekkie:
To further showcase the dynamic capability, we add “Trekkie” as a new binary factor (a factor with only two states). In this case, we create two formulas: one that uses Trekkie as a standalone binary factor, and another that combines both Trekkie and AQI. Again, this is done without any changes to the application code.
Note: The required data is added to MongoDB using a script.
// MongoDB Playground
// Use Ctrl+Space inside a snippet or a string literal to trigger completions.
// The current database to use.
use("hls-calculationdb");
// Function to generate an additive adjustment percentage (0 to 4)
function getAddToAdjustment() {
return parseFloat((Math.random() * 4).toFixed(3));
}
// Function to generate a discount adjustment percentage (-5 to 0)
function getDiscountAdjustment() {
return parseFloat((Math.random() * -5).toFixed(3));
}
// Find a document in a collection.
db["premium-factors"].updateOne(
{ category_id: "0010" },
{
$push: {
factors: {
$each: [
{ factor_id: "binary_006_yes", factor_name: "Trekkie - Yes", adjustment_percentage: getDiscountAdjustment() },
{ factor_id: "binary_006_no", factor_name: "Trekkie - No", adjustment_percentage: getAddToAdjustment() }
]
}
}
}
);
// Switch to the calculation database
use("hls-calculationdb");
// Insert a new formula document that supports Trekkie adjustment
db["premium-formulas"].insertOne({
formula_name: "Base Premium With NicotineUse and Trekkie",
formula_id: "Base-011",
description: "Calculates the base premium based on base rate with adjustments for Gender, Nicotine Use, and the Trekkie binary factor.",
expression_text: "base_rate * (1 + Gender + NicotineUse + Binary.Trekkie)"
});
// Switch to the calculation database
use("hls-calculationdb");
//Insert a new formula document that supports Trekkie adjustment
db["premium-formulas"].insertOne({
formula_name: "Base Premium With NicotineUse, AQI and Trekkie",
formula_id: "Base-012",
description: "Calculates the base premium based on base rate with adjustments for Gender, Nicotine Use, AQI, and the Trekkie binary factor.",
expression_text: "base_rate * (1 + Gender + NicotineUse + AirQuality + Binary.Trekkie)"
});
Restart the Service and run the Trekkie tests:
After updating the configuration for Trekkie, a quick restart refreshes the service cache. Running the Trekkie tests confirms that the new binary factor has been successfully integrated into the Calculation Engine.
Key Takeaways
No Code Changes:
One of the most important aspects of the Calculation Engine is the ability to add new premium factors and corresponding formulas dynamically. Whether it's AQI, Trekkie, or any other factor, the engine adapts automatically once the data is updated. This eliminates the need for code changes, reducing development time and minimizing potential bugs.
Dynamic Formulas:
By using dynamic formulas, the engine immediately adjusts calculations to incorporate any new factors, making the system highly scalable and responsive to evolving business needs.
The Calculation Engine can also incorporate code-based formulas for scenarios where factors cannot be expressed as a simple data element like calling an external service to get Credit Score or something like that. We will demonstrate this capability in our next demo series.
If you like us to test with a premium factor and formula let us know in the comments, we will follow with a short video. Thanks!