Overview
In this article, we'll go over how to use the Assumption Set power to reference parameters used by the engine when writing skills in the PrecisionLender context.
In this Article
- What is the Assumption Set?
- When to use the Assumption Set power
- How to call the Assumption Set power
What is the Assumption Set?
The Assumption Set is a very large object that contains references to rates, products, and other variables that the PrecisionLender engine considers when pricing an opportunity.
When to use the Assumption Set power
You should use the Assumption Set power when writing skills that need to refer to specific product assumptions to either run the skill or return a specific result when your skill runs.
For example, you may want to display a field tag message if your lender adds a Foreign Exchange product to their opportunity. Using the Assumption Set power, you can easily identify the correct product to target your skill.
How to call the Assumption Set power
The assumption set power will be called via the engine property of the PrecisionLender context.
skillContext.powers.precisionlender.engine.assumptionSet.getAssumptionSet()
To view the full set of information available in the Assumption Set, view the definition of .assumptionSet. Here's a snippet of this information:
export interface AssumptionSet { id: Id; regionId: Id; rates: Rates; commercialLoanProducts: CommercialLoanProduct[]; consumerLoanProducts: ConsumerLoanProduct[]; depositProducts: DepositProduct[]; otherProducts: OtherProduct[]; validFrom: string; validThrough: string; cacheKeyId: string; regionalAssumption: RegionalAssumption; fundingPackageSets: FundingPackageSet[]; } export interface FundingPackageSet { fundingPackageGeneration: FundingPackageGeneration; adjustedFundingCurve: AdjustedFundingCurve; } export interface AdjustedFundingCurve { id: Id2; fundingCurveDate: string; created: string; durations: Duration[]; fundingCurveSource: FundingCurveSource; source: string; isValidated: boolean; lastModified: string; unusedLineOpportunityCostTransferDuration: number; unusedLineOpportunityCostLiquidityFactor: number; interpolationMethod: number; adjustPrimeForCostOfFunds: boolean; primeAdjustment: number; liquidityAdjustments: LiquidityAdjustment2[]; maximumCapDuration?: any; capsAndFloorsMethod: number; volatilityEstimates: VolatilityEstimate[]; fundingCurveFamilyForFixedRateSpreadLock: number; hasTermAdjustments: boolean; unusedLineCostOption: number; unusedLineCostRate: number; }
skillmanifest.json
You will enter a description of the skill and any configurations, if applicable, in the skillmanifest.json file. Using our earlier example, the skillmanifest would look like the following:
"description": "This will display the following message to the lender when a Foreign Exchange product is added to the opportunity: Call the FX Desk for pricing information for the "Foreign Exchange" product (x6681).", "skillConfigKeys": []
shouldIRun.ts
You will define the parameters for which your skill should run in the shouldIRun file. For our example, we want the skill to run if the opportunity has a foreign exchange product. We want to run the skill by using the Scenario Recalculated event so that Andi® displays the field tag regardless of what tab you're on (the loan, deposits, or other products) in the opportunity.
export function shouldIRun(skillContext:andiSkills.ISkillContext):Promise{ skillContext.log("shouldIRun for skill: Show Message if Opportunity Has an FX Product."); // run the skill on a Scenario Recalculated event: // The field tag should be displayed across all accounts in the scenario (loans, deposits, and other fee-based accounts). let anEvent = skillContext.powers.andi.event.getApplicationEvent(); let isScenarioRecalculated = anEvent && anEvent.applicationEventName && anEvent.applicationEventName.startsWith("scenarioRecalculated"); if (isScenarioRecalculated) return skillContext.powers.andi.shouldIRun.shouldIRunTrue(); // otherwise, return false return skillContext.powers.andi.shouldIRun.shouldIRunFalse(); }
run.ts
In the run.ts file, you will need to use the Assumption Set power to get the Assumption Set data.
skillContext.powers.precisionlender.engine.assumptionSet.getAssumptionSet()
Continuing with our example, we want to use the Assumption Set to obtain specific product information so that our skill only runs when there is a Foreign Exchange product. Our run.ts file will be written as follows to generate a field tag that displays a message ("Call the FX Desk for pricing information for the "Foreign Exchange" product (x6681)") to the lender if an Foreign Exchange product is added to the opportunity.
// This skill will show a message about how to get help pricing a particular "other fee-based product", // whenever it detects that the particular product exists on the opportunity. // In this example, the name of the particular product we are looking for is "Foreign Exchange", // which is stored in the variable "prodNameToLookFor". // We first use Assumption Set data to get the Product Family Id associated with the product named "Foreign Exchange", // and then we check the opportunity to see whether a product with the matching Product Family Id is present. // run is executed if shouldIRun returns true export function run(skillContext: andiSkills.ISkillContext): Promise { skillContext.log("Running: Show Message If Opportunity Has an FX Product..."); // (To run the skill on a different "other fee-based product", just set the variable "prodNameToLookFor" to a different name.) const prodNameToLookFor = "Foreign Exchange"; // Use the power getAssumptionSet to get the Assumption Set data. return skillContext.powers.precisionLender.engine.assumptionSet.getAssumptionSet() .then((assumptionSet) => { if (assumptionSet && assumptionSet.otherProducts && assumptionSet.otherProducts.length > 0) { // Find the "other fee-based product" in the Assumption Set that has the product name we are looking for. const otherProd = assumptionSet.otherProducts.find((prod) => { return prod.name.toLowerCase() === prodNameToLookFor.toLowerCase(); }); if (otherProd) { // Get the Product Family Id of the product we found. const prodId = otherProd.productFamilyId.id.toLowerCase(); // Now look through the otherFeesAccounts ON THE OPPORTUNITY: // Try to find a product with the same Product Family Id const eventData = (skillContext.event).applicationEventData; const accountOnOpp = eventData.engineModel.otherFeesAccounts.find((account) => { return account.product.productFamilyId.toLowerCase() === prodId; }); // If we found an account on the opportunity with the Product Family Id we're looking for, then send the field tag. // (If none was found, then "accountOnOpp" is undefined and the field tag will not be sent.) if (accountOnOpp) { const messageToDisplay = `Call the FX Desk for pricing information for the "${otherProd.name}" product (x6681)`; return skillContext.powers.andi.fieldTag.sendFieldTag( andiSkills.FieldTagTypes.Info, // this is just a key to uniquely identify your fieldtag "assumption-set-example", 1, messageToDisplay, [], null, function (api, model, comparehash, custom) { // shouldIShow // do not show the message if the data is stale (i.e. if the eventCounter has changed) const eventData = model.applicationEventData; const currentProduct = eventData.engineModel.otherFeesAccounts.find(function (account) { return account.product.productFamilyId.toLowerCase() === custom.prodId; }); var shouldIShow: boolean = (currentProduct); return shouldIShow; }, null, null, { // Pass the local custom value into Andi context prodId: prodId } ); } } // If we made it this far without returning a field tag, then exit gracefully by returning a resolved (and empty) Promise. return {} as andiSkills.ISkillActivity; } }); }
Once the skill has been deployed, your skill manager(s) will be able to enable the skill in the appropriate audience on the skill page. If you wrote your skill with any configurable values or file uploads, those will also be managed on the skill page.