The model builds transient structures to allow the data to be viewed in various ways, to test or find correlations
BPMotor90@ Begin
Control@ begin
!!!!! Parameters:
! r - the number of risk segments - generated automatically in the Database vars
generation block
! q - the number of time preriods per year - f.ex., q=4 means using quarters
q = 4
! h - the number of history periods
h = 4
! p - the number of projection periods
p = 16
! True - model is connected to
generated input variables.
! Make sure it is not true when regenerating the input variables !
ModelActivationSwitch@ EQV MAStep1@
! When set to true, triggers
re-generation of the Database-based input variables
! ( Make sure the model is not active)
ReGenInputDataVars@ EQV Regenerate@
! When set to true, triggers
re-generation of the rest of the input vars
! ( Make sure the model is not active)
ReGenInputVars@ EQV ASK(Regenerate@)
! Connect the data input structure generator to table 1
UseTable1@ begin
ASK(IAveragePastPremium%) =
ASK(IAveragePastPremium%)
ASK( IPastStandingBusiness%) = ASK( IPastStandingBusiness%)
ASK(r) = ASK(r)
ASK(Regenerate@) EQV ASK(Regenerate@)
End !UseTable1@
! Connect the data input structure generator to table2
UseTable2@ begin
ASK(IAveragePastPremium%) =
ASK(IAveragePastPremium%)
ASK( IPastStandingBusiness%) = ASK( IPastStandingBusiness%)
ASK(r) = ASK(r)
ASK(Regenerate@) EQV ASK(Regenerate@)
End !UseTable2@
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Implementation
! model activation sequence
MAStep2@ EQV
SEQUENCE(FeedModelDataBasedVars@,MAStep1@, True, False)
MAStep2Done@ EQV SEQUENCE(FeedModelInputVars@,MAStep2@, True, False)
! FeedDataVariables@ links the
generated data-based input structures to the model
!!!! Make sure the model is not connected to the input vars when regenerated
FeedModelDataBasedVars@ begin
ASK(IAveragePastPremium%) =
ASK(IAveragePastPremium%)
ASK( IPastStandingBusiness%) = ASK( IPastStandingBusiness%)
ASK(r) = ASK(r)
End !FeedModelDataBasedVars@
! FeedInputVariables@ links
the generated and specified additional input structures to the model's
!!!! Make sure the model is not connected to the input vars when regenerated
FeedModelInputVars@ begin
ASK(IInflationPerAnnum%) =
ASK(IInflationPerAnnum%)
ASK(ICommission) = ASK(ICommission)
ASK(IExpenses) = ASK(IExpenses)
ASK(IPremiumIncreaseRates%) = ASK(IPremiumIncreaseRates%)
ASK(INetRenewalsIncrease%) = ASK(INetRenewalsIncrease%)
ASK(INewBusiness%) = ASK(INewBusiness%)
ASK(IAverageClaimCosts%) = ASK(IAverageClaimCosts%)
ASK(IClaimFrequency%) = ASK(IClaimFrequency%)
End !FeedModelInputVars@
End !Control@
! Generate manually input variables
GenerateInputVars@ begin
!!!!!!!! Generation Info -
for each variable specify Mean and SDev
! IPremiumIncreaseRates
IPIRMean = 10
IPIRSDev = 8
! INetRenewalsIncrease
INRIMean = 10
INRISDev = 5
! INewBusiness
INBMean = 12
INBSdev = 5
! IAverageClaimCosts(r,1) - instead, we generate a full h X r percentages and multiply by the actual average premiums found in the data
IACCMean = 0.7
IACCSdev = 0.1
! IClaimFrequency
ICFMEAN = 22
ICFSdev = 5
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Specify Variable Values
! IInflationPerAnnum(1, (h+p)/q) - yearly
IInflationPerAnnum% = {{5,6,5.5}}
! ICommission(1,1)
ICommission = 21
! IExpenses(1,1)
IExpenses = 10
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Auto Generation
! Connect local values of model descriptors
h = ASK(h)
r = ASK(r)
p = ASK(p)
q = ASK(q)
Regenerate@ EQV StartuIPIRP@
! IPremiumIncreaseRates(r, h+p)
DEMON(StartuIPIRP@) EQV
SEQUENCE(DidIPIR@,DoIPIR@,True,False)
DoIPIR@ EQV FORNEST({{iIPIR,1,r}},TestIPIR@,MoveIPIR@,StartuIPIRP@,InitialiseIPIR@)
IF iIPIR = 1 then NewCIPIR% = { EVAL(CurrIPIR%) } else NewCIPIR% = OldCIPIR% + {
EVAL(CurrIPIR%) }
CurrIPIR% = genRandGList(IPIRMean, IPIRSDev, h+p, iIPIR)
TestIPIR@ EQV GETPUT(NewCIPIR%,OldCIPIR%,CurrIPIR%, {temp1%},{})
IPremiumIncreaseRates% = RoundList(temp1%, DidIPIR@)
! INetRenewalsIncrease(r, p/q)
DidIPIR@ EQV StartuINRIP@
DEMON(StartuINRIP@) EQV SEQUENCE(DidINRI@,DoINRI@,True,False)
DoINRI@ EQV FORNEST({{iINRI,1,r}},TestINRI@,MoveINRI@,StartuINRIP@,InitialiseINRI@)
IF iINRI = 1 then NewINRI% = { EVAL(CurrINRI%) } else NewINRI% = OldINRI% + {
EVAL(CurrINRI%) }
CurrINRI% = genRandGList(INRIMean, INRISDev, p DIV q , iINRI)
TestINRI@ EQV GETPUT(NewINRI%,OldINRI%, CurrINRI%, {temp2%},{}
INetRenewalsIncrease% = RoundList(temp2%, DidINRI@)
! INewBusiness(r, p/q)
DidINRI@ EQV StartupINB
DEMON(StartupINB@) EQV SEQUENCE(DidINB@,DoINB@,True,False)
DoINB@ EQV FORNEST({{iINB,1,r}},TestINB@,MoveINB@,StartupINB@,InitialiseINB@)
IF iINB = 1 then NewINB% = { EVAL(CurrINB%) } else NewINB% = OldINB% + { EVAL(CurrINB%) }
CurrINB% = genRandGList(INBMean, INBSDev, p DIV q , iINB)
TestINB@ EQV GETPUT(NewINB%,OldINB%, CurrINB%, {temp3%},{})
INewBusiness% = RoundList(temp3%, DidINB@)
! IAverageClaimCosts(r,1) - instead, we generate a full (r,h) percentages and multiply by the actual average premiums found in the data
DidINB@ EQV StartupIACC@
DEMON(StartupIACC@) EQV SEQUENCE(DidIACC@,DoIACC@,True,False)
DoIACC@ EQV FORNEST({{iIACC,1,r}},TestIACC@,MoveIACC@,StartupIACC@,InitialiseIACC@)
IF iIACC = 1 then NewIACC% = { EVAL(CurrIACC%) } else NewIACC% = OldIACC% + {
EVAL(CurrIACC%) }
CurrIACC% = genRandGList(IACCMean, IACCSDev, h , iIACC)
TestIACC@ EQV GETPUT(NewIACC%,OldIACC%, CurrIACC%,{IAverageClaimCosts%},{})
! IClaimFrequency(r, 1)
DidIACC@ EQV StartupICF@
DEMON(StartupICF@) EQV SEQUENCE(DidICF@,DoICF@,True,False)
DoICF@ EQV FORNEST({{iICF,1,r}},TestICF@,MoveICF@,StartupICF@,InitialiseICF@)
IF iICF = 1 then NewICF% = { EVAL(CurrICF%) } else NewICF% = OldICF% + { EVAL(CurrICF%) }
CurrICF% = genRandGList(ICFMean, ICFSDev, 1 , iICF)
TestICF@ EQV GETPUT(NewICF%,OldICF%, CurrICF%, {temp4%},{})
IClaimFrequency% = RoundList(temp4%, DidICF@)
End !GenerateInputVars@
MainBPModel@ begin
! A small device to turn all Tr@'s triggers on
AllTrs% = GROUP('NAME TR*?', TurnTrsOn@)
EQV@( {True} + AllTrs% )
! Connect static parameters
q=ASK(q)
p=ASK(p)
h=ASK(h)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
MODIFIED INPUT VAR
! IYNetRenewalsIncrease - expansion of INetRenewalsIncrease% from a yearly basis to a full
periods basis, the h periods
! are assigned 0
temp1% =
ExpandList(INetRenewalsIncrease%,q,tr11@)
temp2% = MAKE2DLIST(r,q,'Numeric',tr12@)
IYNetRenewalsIncrease% = CombineLists(temp2%,temp1%,tr13@)
! IYNewBusiness - expansion of
INewBusiness% from a yearly basis to a full periods basis, the h periods
! are assigned 0
temp3% = ExpandList(INewBusiness%,q,tr14@)
temp4% = MAKE2DLIST(r,q,'Numeric',tr15@)
IYNewBusiness% = CombineLists(temp4%,temp3%,tr16@)
! IYInflationPerAnnum - expansion
of IInflationPerAnnum% from a yearly basis to a full periods basis, the h periods
! are assigned 0
IYInflationPerAnnum% = ExpandList(IInflationPerAnnum%,q,tr17@)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
CALCULATED VARS
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Premiums
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Accumulated Premium Increase Rate
temp55% =
ListOp('/',IPremiumIncreaseRates%,100,tr18@)
temp6% = ListOp('+',temp55%,1,tr19@)
CPremiumIncreaseRates% = FactorialList(temp6%,4,tr20@)
! Projected Premiums -
itterative: multiply the 'h year' premiums by the accumulated increase in year 1 and get
projected premiums
! for year 1. Then, multiply it by the accumulated increase in year 2 and get the
projection for year 2, etc.
! Perform only when IAveragePastPremiums% and CPremiumIncreaseRates% are known
! The base structures become knows resets StartupPP@
( Tr46@ AND Logstate(IAveragePastPremium%) AND Logstate(CPremiumIncreaseRates%) ) EQV StartupPP@
! Resetting StartupPP@ initiates a search on the SEQUENCE, which triggers the FORNEST by a search on its value, and then pushes a True on Did... then a true on the trigger
Demon(StartupPP@) EQV
SEQUENCE(DidProjPremium@,DoProjPremium@,True,false)
DoProjPremium@ EQV FORNEST({{iPP,0,( p DIV q) }},TestPP@,MovePP@,StartupPP@,InitialisePP@)
if iPP = 0 then NewCCAP% = IAveragePastPremium% else NewCCAP% =
CombineLists(OldCCAP%,temp9%)
if iPP > 0 then temp7% = sub2DList(OldCCAP%,(iPP-1)*q+1,q)
temp8% = sub2DList(CPremiumIncreaseRates%,iPP*q+1,q)
temp9% = ListOp('*',temp7%, temp8%)
TestPP@ EQV GETPUT(NewCCAP%,OldCCAP%, iPP, { temp91%},{})
! Assign the value only after the FORNEST is finishe
DidProjPremium@ EQV (CCurrentAveragePremiums% = temp91%)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Renewals !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Projected Renewals - itterative: for the first q periods use the input
IPastStandingBusiness%. To get year 1 renewals multiply the year
! 1 IYNetRenewalsIncrease% by the h year renewals. Then, for year 2 renewals multiply the
year 1 renewals by year 2 IYNetRenewalsIncrease%, etc.
temp10% = ListOp('/',IYNetRenewalsIncrease%,100)
temp11% = ListOp('+',temp10%,1)
( Tr47@ AND Logstate(temp11%) AND Logstate(IPastStandingBusiness%) ) EQV StartuPRP@
Demon(StartuPRP@) EQV SEQUENCE(DidProjRenewals@,DoProjRenewals@,True,false)
DoProjRenewals@ EQV FORNEST({{iPR,0,( p DIV q)}},TestPR@,MovePR@,StartuPRP@,InitialisePR@)
if iPR = 0 then NewCSB% = IPastStandingBusiness% else NewCSB% =
CombineLists(OldCSB%,temp14%)
if iPR > 0 then temp12% = sub2DList(OldCSB%,(iPR-1)*q+1,q)
temp13% = sub2DList(temp11%,iPR*q+1,q)
temp14% = ListOp('*',temp12%, temp13%)
TestPR@ EQV GETPUT(NewCSB%,OldCSB%, iPR, {temp15%},{})
! Continue after the loop is finished
temp16%=RoundList(temp15%,DidProjRenewals@,
tr21@)
CStandingBusiness%=ListOp('max',temp16%,0)
! Projected New Business
temp18% = ShiftListRight(CStandingBusiness%,4)
temp17% = sub2DList(temp18%,1,h+p)
temp19% = ListOp('/',IYNewBusiness%,100)
CNewBusiness% = ListOp('*',CStandingBusiness%,temp19%)
! Lapses
temp20% =
ListOp('-',IYNewBusiness%,IYNetRenewalsIncrease%, tr22@)
temp21% = ListOp('/',temp20%,100)
temp211% = ListOp('*',temp21%,CStandingBusiness%)
CLapses% = RoundList(temp211%, tr211@)
! Exposure
temp22% = ListOp('/',CStandingBusiness%,8,tr23@)
temp23% = ListOp('/',CStandingBusiness%,4,tr24@)
CExposure% = specialSum(temp22%,temp23%,temp23%,temp23%,temp22%,tr25@)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Claims !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Projected Claim Cost
! First create CInflationFactors%
temp24% = ListOp('/',
IYInflationPerAnnum%,100,tr26@)
temp25% = ListOp('+',temp24%,1,tr27@)
temp26% = ListOp('Root',temp25%,q,tr28@)
( Tr48@ AND Logstate(temp26%)) EQV StartuIFP@
Demon(StartuIFP@) EQV SEQUENCE(DidInflationFactors@,DoInflationFactors@,True,false)
DoInflationFactors@ EQV FORNEST({{iIF,0,r}},TestIF@,MoveIF@,StartuIFP@,InitialiseIF@)
if iIF = 0 then NewCIF% = {} else NewCIF% = OldCIF% + { EVAL(temp26%) }
TestIF@ EQV GETPUT(NewCIF%,OldCIF%, iIF, {temp261%},{})
DidInflationFactors@ EQV (CInflationFactors% = temp261%)
! Now, create
CInflationLinkedAverageCost%
! temp30% = ExpandList(IAverageClaimCosts%,q, tr29@)
! For Auto Generation of input only - generate claims costs as a percentage of the actual
premiums
temp30% =
ListOp('*',IAverageClaimCosts%,IAveragePastPremium%, tr29@)
( Tr49@ AND Logstate(temp30%) AND Logstate(CInflationFactors%) ) EQV StartupCILAC@
Demon(StartupCILAC@) EQV SEQUENCE(DidProjClaimCost@,DoProjClaimCost@,True,false)
DoProjClaimCost@ EQV FORNEST({{iCILAC,0,( p DIV q)
}},TestCILAC@,MoveCILAC@,StartupCILAC@,InitialiseCILAC@
if iCILAC = 0 then NewCILAC% = temp30% else NewCILAC% = CombineLists(OldCILAC%,temp29%)
if iCILAC > 0 then temp27% = sub2DList(OldCILAC%,(iCILAC-1)*q+1,q)
temp28% = sub2DList(CInflationFactors%,iCILAC*q+1,q)
temp29% = ListOp('*',temp27%, temp28%)
TestCILAC@ EQV GETPUT(NewCILAC%,OldCILAC%, iCILAC, {temp301%},{})
DidProjClaimCost@ EQV (CInflationLinkedAverageCost% = temp301%)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
FORECASTING
! Written Premiums
CWrittenPremiums% = ListOp('*',CStandingBusiness%, CCurrentAveragePremiums%, tr30@)
! Earned Premiums
temp31% = ListOp('/',CWrittenPremiums%,8,tr31@)
temp32% = ListOp('/',CWrittenPremiums%,4,tr32@)
CEarnedPremium% = specialSum(temp31%,temp32%,temp32%,temp32%,temp31%,tr33@)
! Total Number Of Claims
temp33% = ListOp('/',
IClaimFrequency%,100,tr34@)
temp34% = ListOp('+',temp33%,1,tr35@)
temp35% = ExpandList(temp34%,h+p, tr36@)
temp36% = ListOp('*',CExposure%,temp35%, tr37@)
CTotalNumberClaims% = RoundList(temp36%, tr38@)
! Total Claim Cost
CTotalclaimCost% = ListOp('*',CInflationLinkedAverageCost%,CTotalNumberClaims%, tr39@)
! CommissionExpenses
CCommissionExpenses% = ListOp('*',CWrittenPremiums%,ICommission/100, tr40@)
! OtherExpenses
COtherExpenses% = ListOp('*',CWrittenPremiums%,IExpenses/100, tr41@)
! Loss Ratio
CLossRatio% = ListOp('/',CTotalclaimCost%,CEarnedPremium%,0.01, tr42@)
! Expense Ratio
temp37% =
ListOp('+',CCommissionExpenses%,COtherExpenses%, tr43@)
CExpenseRatio% = ListOp('/',temp37%,CWrittenPremiums%,0.01, tr44@)
! Combined Operating Ratio
CCombinedOperatingRatio% = ListOp('+',CLossRatio%,CExpenseRatio% ,tr45@)
End !MainBPModel@
BPMotor@ Begin
cascopol97@ Begin
!!! Specify the columns used to define the segments
IndexColumns%= {{Age},{CC}}
ColumnsValues% = { { EVAL(Age), EVAL(CC) } }
IndexColumnsC% = { {ProductionMonth} }
! Trigger regeneration
Regenerate@ EQV StartupR@
GenPastPremiums2@ EQV DEMON(StartupR@)
! A list of the columns that are
used to define the risk segments
! IndexColumns% can come from different database tables
IndexListR% = IndexColumns% + {{AllSetR,1,1}}
! Go over the combinations, for each one trigger a row generation, when done - append it
GenPastPremiums2@ EQV
FORNEST(IndexListR%,TestR@,MoveR@,StartupR@,InitialiseR@)
If InitialiseR@ then NewIAPP% = { EVAL(CurrentRiskSegment%)} else NewIAPP% = OldIAPP% + {
EVAL(CurrentRiskSegment%) }
If InitialiseR@ then NewNP% = { EVAL(CurrentRiskNumPolicies%)} else NewNP% = OldNP% + {
EVAL(CurrentRiskNumPolicies%) }
If InitialiseR@ then NewRisks% = ColumnsValues% else NewRisks% = OldRisks% +
ColumnsValues%
DidIAPP@ EQV GETPUT(NewIAPP%,OldIAPP%,DoGETPUTPP@,{IAveragePastPremium%},{})
DidNP@ EQV GETPUT(NewNP%,OldNP%,DoGETPUTNP@,{IPaststandingBusiness%},{})
DidRisks@ EQV GETPUT(NewRisks%,OldRisks%,DoGETPUTRisks@,{Risks%},{})
DidGetPuts@ EQV SEQUENCE(DoGETPUTPP@ AND DoGetputNP@ AND
DoGETPUTRisks@,GenPastPremiums3@,True,False)
TestR@ EQV ( DidGetPuts@ AND DidIAPP@ AND DidNP@ AND DidRisks@)
! Generate rows
! IndexColumnsC%, the time segmentation column, can come from different database tables
IndexListC% = IndexColumnsC% + {{AllSetC,1,1}}
CurrentRiskSegment% = Make1DList(q,'NUMERIC',0,AllSetR)
CurrentRiskNumPolicies% = Make1DList(q,'NUMERIC',0,AllSetR)
StartupC@ EQV LogState(CurrentRiskSegment%) AND LogState(CurrentRiskNumPolicies%)
GenPastPremiums3@ EQV DEMON(StartupC@)
GenPastPremiums3@ EQV FORNEST(IndexListC%,TestC@,MoveC@,StartupC@,InitialiseC@)
CurrentIndex=EXTRACT(ProductionMonth,'MaxPosition',1)
CurrentVal = EXTRACT(IndexedNetPremium,'MEAN',1
CurrentNumPolicies = EXTRACT(ProductionMonth,'MAX',1)
J = setvargapind(CurrentRiskSegment%,CurrentIndex,CurrentVal,AllSetC)
JJ = setvargapind(CurrentRiskNumPolicies%,CurrentIndex,CurrentNumPolicies,AllSetC)
TestC@ EQV logstate(j) AND logstate(jj)
! q is defined by the user in the control block
q = ASK(q)
! r is the number of risk segments found
r=size(IAveragePastPremium%)
End !cascopol97@
End !BPMotor@
MSACCESS1@ Begin
Cascopol972k@ Begin
!!! Specify the columns used to define the segments
IndexColumns%= {{Age},{CC}}
ColumnsValues% = { { EVAL(Age), EVAL(CC) } }
IndexColumnsC% = { {ProductionMonth} }
! Trigger regeneration
Regenerate@ EQV StartupR@
GenPastPremiums2@ EQV DEMON(StartupR@)
! A list of the columns that are
used to define the risk segments
! IndexColumns% can come from different database tables
IndexListR% = IndexColumns% + {{AllSetR,1,1}}
! Go over the combinations, for each one trigger a row generation, when done - append it
GenPastPremiums2@ EQV
FORNEST(IndexListR%,TestR@,MoveR@,StartupR@,InitialiseR@)
If InitialiseR@ then NewIAPP% = { EVAL(CurrentRiskSegment%)} else NewIAPP% = OldIAPP% + {
EVAL(CurrentRiskSegment%) }
If InitialiseR@ then NewNP% = { EVAL(CurrentRiskNumPolicies%)} else NewNP% = OldNP% + {
EVAL(CurrentRiskNumPolicies%) }
If InitialiseR@ then NewRisks% = ColumnsValues% else NewRisks% = OldRisks% +
ColumnsValues%
DidIAPP@ EQV GETPUT(NewIAPP%,OldIAPP%,DoGETPUTPP@,{IAveragePastPremium%},{})
DidNP@ EQV GETPUT(NewNP%,OldNP%,DoGETPUTNP@,{IPaststandingBusiness%},{})
DidRisks@ EQV GETPUT(NewRisks%,OldRisks%,DoGETPUTRisks@,{Risks%},{})
DidGetPuts@ EQV SEQUENCE(DoGETPUTPP@ AND DoGetputNP@ AND
DoGETPUTRisks@,GenPastPremiums3@,True,False)
TestR@ EQV ( DidGetPuts@ AND DidIAPP@ AND DidNP@ AND DidRisks@)
! Generate rows
! IndexColumnsC%, the time segmentation column, can come from different database tables
! q is defined by the user in the control block
q = ASK(q)
! r is the number of risk segments found
r=size(IAveragePastPremium%)
End !Cascopol972k@
End !MSACCESS1@
End !BPMotor90@