@@ -500,6 +500,27 @@ object Simulation:
500500 base * erAdj * trendAdj * cyclicalAdj
501501 else 0.0
502502
503+ // Tourism services export/import (#47)
504+ val (tourismExport, tourismImport) = if Config .TourismEnabled then
505+ val monthInYear = (m % 12 ) + 1
506+ val seasonalFactor = 1.0 + Config .TourismSeasonality *
507+ Math .cos(2 * Math .PI * (monthInYear - Config .TourismPeakMonth ) / 12.0 )
508+ val inboundErAdj = Math .pow(w.forex.exchangeRate / Config .BaseExRate , Config .TourismErElasticity )
509+ val outboundErAdj = Math .pow(Config .BaseExRate / w.forex.exchangeRate, Config .TourismErElasticity )
510+ val trendAdj = Math .pow(1.0 + Config .TourismGrowthRate / 12.0 , m.toDouble)
511+ val disruption = if Config .TourismShockMonth > 0 && m >= Config .TourismShockMonth then
512+ Config .TourismShockSize * Math .pow(1.0 - Config .TourismShockRecovery ,
513+ (m - Config .TourismShockMonth ).toDouble)
514+ else 0.0
515+ val shockFactor = 1.0 - disruption
516+ val baseGdp = Math .max(0.0 , w.gdpProxy)
517+ val inbound = Math .max(0.0 , baseGdp * Config .TourismInboundShare *
518+ seasonalFactor * inboundErAdj * trendAdj * shockFactor)
519+ val outbound = Math .max(0.0 , baseGdp * Config .TourismOutboundShare *
520+ seasonalFactor * outboundErAdj * trendAdj * shockFactor)
521+ (inbound, outbound)
522+ else (0.0 , 0.0 )
523+
503524 // Consumer credit flows
504525 val aggConsumerDS = w.bank.consumerLoans * (Config .CcAmortRate + (lendingBaseRate + Config .CcSpread ) / 12.0 )
505526 val aggConsumerOrig = domesticCons * 0.02 // ~2% of consumption financed by credit
@@ -629,7 +650,9 @@ object Simulation:
629650 gvcIntermImports = gvcImp,
630651 remittanceOutflow = remittanceOutflow,
631652 euFundsMonthly = euMonthly,
632- diasporaInflow = diasporaInflow)
653+ diasporaInflow = diasporaInflow,
654+ tourismExport = tourismExport,
655+ tourismImport = tourismImport)
633656 (oeResult.forex, oeResult.bop, oeResult.valuationEffect, oeResult.fxIntervention)
634657 else
635658 val fx = Sectors .updateForeign(w.forex, importCons, totalTechAndInvImports, autoR, w.nbp.referenceRate, gdp, rc)
@@ -818,6 +841,7 @@ object Simulation:
818841 + corpBondBankCoupon * 0.3 ,
819842 deposits = w.bank.deposits + (totalIncome - consumption) + jstDepositChange
820843 + netDomesticDividends - foreignDividendOutflow - remittanceOutflow + diasporaInflow
844+ + tourismExport - tourismImport
821845 + consumerOrigination + insNetDepositChange + nbfiDepositDrain,
822846 consumerLoans = Math .max(0.0 , w.bank.consumerLoans + consumerOrigination - consumerPrincipal - consumerDefaultAmt),
823847 consumerNpl = Math .max(0.0 , w.bank.consumerNpl + consumerDefaultAmt - w.bank.consumerNpl * 0.05 ),
@@ -909,9 +933,11 @@ object Simulation:
909933 val bankDivOutflow = foreignDividendOutflow * ws
910934 val bankRemittance = remittanceOutflow * ws
911935 val bankDiasporaInflow = diasporaInflow * ws
936+ val bankTourismExport = tourismExport * ws
937+ val bankTourismImport = tourismImport * ws
912938 val bankInsDepChange = insNetDepositChange * ws
913939 val bankNbfiDepDrain = nbfiDepositDrain * ws
914- val newDep = b.deposits + (bankIncomeShare - bankConsShare) + bankDivInflow - bankDivOutflow - bankRemittance + bankDiasporaInflow + bankCcOrig + bankInsDepChange + bankNbfiDepDrain
940+ val newDep = b.deposits + (bankIncomeShare - bankConsShare) + bankDivInflow - bankDivOutflow - bankRemittance + bankDiasporaInflow + bankTourismExport - bankTourismImport + bankCcOrig + bankInsDepChange + bankNbfiDepDrain
915941 // Per-bank mortgage flows (proportional to deposit share)
916942 val bankDepShare = if totalWorkers > 0 then perBankWorkers(bId) / totalWorkers else 0.0
917943 val bankMortgageIntIncome = mortgageInterestIncome * bankDepShare
@@ -1077,7 +1103,9 @@ object Simulation:
10771103 aggEnergyCost = sumEnergyCost,
10781104 aggGreenCapital = aggGreenCapital,
10791105 aggGreenInvestment = sumGreenInvestment,
1080- diasporaRemittanceInflow = diasporaInflow)
1106+ diasporaRemittanceInflow = diasporaInflow,
1107+ tourismExport = tourismExport,
1108+ tourismImport = tourismImport)
10811109
10821110 // SFC accounting check: verify exact balance-sheet identities every step
10831111 val prevSnap = SfcCheck .snapshot(w, firms, households)
@@ -1137,7 +1165,9 @@ object Simulation:
11371165 nbfiDefaultAmount = finalNbfi.lastNbfiDefaultAmount,
11381166 fdiProfitShifting = sumProfitShifting,
11391167 fdiRepatriation = sumFdiRepatriation,
1140- diasporaInflow = diasporaInflow
1168+ diasporaInflow = diasporaInflow,
1169+ tourismExport = tourismExport,
1170+ tourismImport = tourismImport
11411171 )
11421172 val sfcResult = SfcCheck .validate(m, prevSnap, currSnap, sfcFlows)
11431173 if ! sfcResult.passed then
0 commit comments