From 91e511a03e3af641d3a1cf918724497f6360ef28 Mon Sep 17 00:00:00 2001 From: jaehyukchoi Date: Fri, 27 May 2022 20:59:30 +0800 Subject: [PATCH 1/2] OusvUncorrBallRoma1994 implemented --- pyfeng/__init__.py | 1 + pyfeng/ousv.py | 73 ++++++++++++++++++++++++++++------------------ 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/pyfeng/__init__.py b/pyfeng/__init__.py index a1944ac..23d6b1c 100644 --- a/pyfeng/__init__.py +++ b/pyfeng/__init__.py @@ -13,6 +13,7 @@ SabrChoiWu2021P, ) from .garch import GarchMcTimeStep, GarchUncorrBaroneAdesi2004 +from .ousv import OusvUncorrBallRoma1994 from .sabr_int import SabrUncorrChoiWu2021 from .sabr_mc import SabrMcCond from .nsvh import Nsvh1, NsvhMc diff --git a/pyfeng/ousv.py b/pyfeng/ousv.py index 61d3733..fc8b853 100644 --- a/pyfeng/ousv.py +++ b/pyfeng/ousv.py @@ -2,9 +2,34 @@ import numpy as np import scipy.integrate as scint from . import sv_abc as sv +from . import bsm -class OusvSchobelZhu1998(sv.SvABC): +class OusvABC(sv.SvABC, abc.ABC): + model_type = "OUSV" + + def avgvar_mv(self, var_0, texp): + """ + Mean and variance of the variance V(t+dt) given V(0) = var_0 + (variance is not implemented yet) + + Args: + var_0: initial variance + texp: time step + + Returns: + mean, variance(=NULL) + """ + + mr_t = self.mr * texp + e_mr = np.exp(-mr_t) + x0 = var_0 - self.theta + vv = self.vov**2/2/self.mr + self.theta**2 + \ + ((x0**2 - self.vov**2/2/self.mr)*(1 + e_mr) + 4*self.theta * x0)*(1 - e_mr)/(2*self.mr*texp) + return vv, None + + +class OusvSchobelZhu1998(OusvABC): """ The implementation of Schobel & Zhu (1998)'s inverse FT pricing formula for European options the Ornstein-Uhlenbeck driven stochastic volatility process. @@ -13,18 +38,15 @@ class OusvSchobelZhu1998(sv.SvABC): - Schöbel, R., & Zhu, J. (1999). Stochastic Volatility With an Ornstein–Uhlenbeck Process: an Extension. Review of Finance, 3(1), 23–46. https://doi.org/10.1023/A:1009803506170 Examples: - >>> import pyfeng as pfex - >>> model = pfex.OusvSchobelZhu1998(0.2, mr=4, vov=0.1, rho=-0.7, intr=0.09531) + >>> import pyfeng as pf + >>> model = pf.OusvSchobelZhu1998(0.2, mr=4, vov=0.1, rho=-0.7, intr=0.09531) >>> model.price(100, 100, texp=np.array([1, 5, 10])) array([13.21493, 40.79773, 62.76312]) - >>> model = pfex.OusvSchobelZhu1998(0.25, mr=8, vov=0.3, rho=-0.6, intr=0.09531) + >>> model = pf.OusvSchobelZhu1998(0.25, mr=8, vov=0.3, rho=-0.6, intr=0.09531) >>> model.price(np.array([90, 100, 110]), 100, texp=1) array([21.41873, 15.16798, 10.17448]) """ - model_type = "OUSV" - var_process = False - def D_B_C(self, s1, s2, s3, texp): # implement the formula for D(t,T), B(t,T), C(t,T) in paper appendix mr, theta, vov = self.mr, self.theta, self.vov @@ -106,9 +128,22 @@ def price(self, strike, spot, texp, cp=1): return df * fwd * price -class OusvMcABC(sv.SvABC, sv.CondMcBsmABC, abc.ABC): +class OusvUncorrBallRoma1994(OusvABC): + + def price(self, strike, spot, texp, cp=1): + + if not np.isclose(self.rho, 0.0): + print(f"Pricing ignores rho = {self.rho}.") + + avgvar, _ = self.avgvar_mv(self.sigma, texp) + m_bs = bsm.Bsm(np.sqrt(avgvar), intr=self.intr, divr=self.divr) + price = m_bs.price(strike, spot, texp, cp) + + return price + + +class OusvMcABC(OusvABC, sv.CondMcBsmABC, abc.ABC): - model_type = "OUSV" var_process = False @abc.abstractmethod @@ -156,26 +191,6 @@ def cond_spot_sigma(self, vol_0, texp): sigma_cond = np.sqrt((1 - self.rho**2) * var_mean) / vol_0 return spot_cond, sigma_cond - def avgvar_mv(self, var_0, texp): - """ - Mean and variance of the variance V(t+dt) given V(0) = var_0 - (variance is not implemented yet) - - Args: - var_0: initial variance - texp: time step - - Returns: - mean, variance - """ - - mr_t = self.mr * texp - e_mr = np.exp(-mr_t) - x0 = var_0 - self.theta - vv = self.vov**2/2/self.mr + self.theta**2 + \ - ((x0**2 - self.vov**2/2/self.mr)*(1 + e_mr) + 4*self.theta * x0)*(1 - e_mr)/(2*self.mr*texp) - return vv - class OusvMcTimeStep(OusvMcABC): """ From e0cca6d8155694867fea73531849ae865f53e26d Mon Sep 17 00:00:00 2001 From: jaehyukchoi Date: Fri, 27 May 2022 21:00:42 +0800 Subject: [PATCH 2/2] added schobel & zhu examples --- pyfeng/data/ousv_benchmark.xlsx | Bin 16447 -> 25686 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pyfeng/data/ousv_benchmark.xlsx b/pyfeng/data/ousv_benchmark.xlsx index 2bbc0cfa93565af56c841f3b6efc42256b9d6a7a..1fcc28dcd6c70f3dab45b165ab67ff2a15eb2b84 100644 GIT binary patch delta 13859 zcmZvjWmp`|wzda%cbDL90fM_b0fM_ja0%A9Lx90Ua0|iR-QC?Kgy6ybBiZMickg|D z{bQ!8=c&4;?XG84t?uxLm>-0|SCNN;#sI?82cB*Bm5w%r4lwNrk8*w^O1abb44u2tn~7&maH2(7UI8v&|y)JQeS&#VXgYViJ?zB=g7TDG1%88)SN8 zs3~~7q-w2&XEe0lYFSjyrpL8A9-i`EGM;+Wl{}1Py&;U5Ly>3>jrC4J0vKOzd4V%O z0|&gN8>`z z?Ks`+gvpSj&4I}b#xTMNX@ieQ(TZRu9%%jQ%Q(7>#k8_Q4zS% zAES()Z426))eXqzX(WN*Vl?=XMjxNW$ z?1u683l-bU61AG6_JcdXqBuA;KcT3h0Ms3K;|(YfhyW1;LVLZqo_4Gr4$ihF4i2^~ zp7wU7nz{~oyx4w*)-O=oUjv(9XU(`)Eg0)GW{2uo;~C%-MEC0ZxgtvLPQ4Yn3x=!` zkL?mc^}>Kq$|&dD4<5Ut%VSn&gYw`%{V(5!$8Qm|>tG&m0t72Cz zVEPdI9y@Zd=@UI;B+t9XHu2C(An)w$Rv30;@sn(&tNZ(S$y%F|V10->AGZ5ZAb$|v z7ryI605*mFfP>nBU}DP%=dG}H(mThrHw0>aUr+*S`O0|FTa~K`g6vBg8 zW$59upWBo{?_bEk&@qu}EiudP$usQu-W0ncOPCh}~}DVJR-Vz|ku=d`=2Skudd zqmw=%xuFe=d|3WCKjMqO3g|981Shf{;&ZlU7Gq_lbOV#Lv5hkvp1zewXFh}wY;k;T zuqn}qXFfX{Vx;XmJcEe4fRGUGF-kCr^@OrlmFVS#|dIszAQ+cm!hJ@p^5;Ocr zLTGn%&&VgJjGRI&jYjhW_N@#rmS1seH3j^whgxylwb}yd=jFu0m>pSq_jP2e#_P+Z zoYnSH)@M1D-owL<%j1#=PNJv6s10k|>bN!78MSUW-#Kp%XXPr}w1l!H#T zvi^=x@#9k2d7HrhsCS+m9;HM=2~#_ z3QiDhUmA2tox`!+ZZR%tq*inP)}zQ=0Et*S3!Z#-L~--F{nu!27r){?JslieDg z`s6m|s+c6OrUli5_}KZ@Q}GhE3 zIOj21mDDG*Z|B4iq9f?$T@yO7kOBPV$*HCXo{2-y+=cq0+gX+uqsP+b zf|9s%R!?6C2rPz!jaX}?e`@rKb2WsTZA5yASDxGUupx(@20evsKK#nxAW`&Q#J{W@ znSTOp70X(gz^yzCc4Q6J*M{Wo8TlZ{^iTIZL=GMvYw1gp6)S!-8%|IirA!nvFBnz7 zt_PZRs|P>C5xkc(8P?&lYiVlJ?l6Lx*XNL2N*&aQr!fzy8x!1@!u}9M@C~+r{~et^ z5agCK{t0Ru{@rgU;)y1qiY{)vw|V->9Bm_dFTN{{<1Y)EVdC^>su4GY1#Q!T0D~_V zOs<=x=)RTud=c`gQt}(=(Ob7vvu$wyV!gBTHJvc~+=lG~goy%Os-%%6Za$}J7T5e3 zYi9I;*t#zkVmD(C$h$wE(j_YrzPMLh2ckgW+jNmkWT&{;{fo z%&3fg>$L03m1S*QK*-GFdTJxmQEat&q7Z-y9p5z}j%I&avo ztUoU<$xu2x5$xN+Q`9(!Rn<9~T(BSzCIMI!p8)KL0te_jEVE&Up3)u*OSDhm1!Gf+ z&52Bv9Ov5HIN4`lnP3d0*(16x0~--o*@WOw1`OxzTY-Jw&&LW5H@VIRBGxR2iNOXU z#Kmc&pW2j$8Y<*H6o~DuzRt+a$0a~nIrBf<8aIP&^5j7~;7^fA_$8w;h-qII-H z#pj9?NkBF%+1&C%3}pHWmFis(dAP6WCq+K7+;Zc=+)ZTM1bdj-!XUchV$rAO-58;1 z=oVPo;$=Ic6xk_qlRn0esJL>(T?t`s%sBcQKfTGM65n};bU+yNm=f^&smeMQ<|l`o z#~pd3vmPryMkp^uxE{PPDB#~A8hEz&Th4C!CIH=25pQ{WLQjMHXg{p5B-wq+Ofc-S zA~tuzZ#3p=^2qDsaH)}XJ!RP;Pq(~aN?+~m7_v)u(c79&%FC7+(ogk472lpHbcgcY zubgo(8JL{oeBX&|6d%WX{H!P2WKAoysp3BvI=^|8MWkoWzwd||W7jTX{6j^9erQs_ zJQV2Yd}EPsMjaEs9Z?}~svOi+B{rm0Tt=!}kF)$+J+Ro%X5eR9vFuB&X7zZ#p|yUz zW^a{eif5R~y#%uE%ZtL1+_vq@Y*xd0m6p6WDOnO&T(lwSQ$maKBwh76`j z-sUwV*U*^5tBihgiy`7JH?rcf@a1Y;&pSr+2cDw<_$s5Nen;CW%Y150QXF>LU-CN{#Juuoe84#MD@*R^V0xSw+PZ7GIAG$t$fzg^cp4>}Mg~@GX)SC$ zXxhs|$u*XWw=o%s%%No5)??D% zQeB;AKCLDCf3CL~39#rCqvkB}c>Bwcj zj?D&9lpL1Gn&Ss)j)(l0q)T$;V2?)3`D5RO&X!@9Q9?BAy=4v^2tzUVG&C-CFUzi# zr@W+$pt$YS71VGJ-?QG#MT@A8@FN6~#hcW}tjd`xIlVBHn02w}&H!?&t*wj(3-o1% z3-mbUkMvL0p0Ja)c1{Ih(x~i9CJo0ULV80q%Q(CIYNJ0Q)hjU?rjv5V%B`rIxAmuR z3f#03-JJ>+7PsZlJ`A6S?55El~qC=QMpjmuVf(TvaDU z(i%_OD~Y-K@-mzWOP*%L<)Ko;eX4m=*V{Ev(~x$Z2|4OqF;MS$)p}jO6gNiH^nJhM z8bObKz6R}*Nm)AOltsC^9#Q+|-Q-NJ52x8Wf2X1_C!cBykB0qup^--Px>cFyp1*gD zue&12slK|jQxIPy|F;=id-Wn(+1WJKeYv&4*1`w0ntqHNWW-OTztsz1K%i5sKP(5h z|9IvM@Ji%sJQRA0P5xV>Lf#@ST<;5s&69E4Q>sr;>u1UM_W0ayR^n5DWT)H=rk*HY+A)i8X zzDThdSl6q!x>$y9CGZVy)aN#6rJGD_V!vI{Cu1w~5-APAKH(B!S1bKs&u9NrM{I3? zw*Z+0MF62S@B1j*OLjgq=kl-q5D}XF46>1|IE0)dDX-EOdW8(ko||s6O@4sk?t|R< zZNJ>QaUNQCHPNU;3cY(S%XwDoFs|&|EVvQLbl3y=L^!Zr8jMELeiW~q^ickNl;w<0 zC&EKX+?Ha*zSBALfEhQ*l^awaHK3TA-|zX1{Odwr9Fk3XYJwnZP=dC#VPDuYYzXx`sEfQ-j{g@L6iZN z_8Vo@EQXH+_;{Ge(xwyUI*`!qG6;aXr8=Mx)S>#f;xz5CmXuZ<_{MqKdS%cCHlGG}HCO9!e0-opY`%F<6Xt+1V$i;W+y z?=sidiwH&v#(xb>#dqk|`?^-W7}~PX?AQttka;`)$S>5!cv3e9LL*Oz9kcOs5U1vc^AdI1u!7na$ z^B4MrV^W)RD``bEZH$9G$t|K#xOL+c&TBJvX#Bm*%xJ`A zq2FrPLeJf0M$C9oiZwS_xn_7<_{eSS*F5aB_PC37_tgGZfrhvMJuV2fz!0)YTnR?c zPg(U;=`66ntZ}TYI@8GuI=^t6^(+H#Mis+DMjpaeF%>s)`2#%zuCaPYk0q$DzlR-Z z>ARSFegnP^qrC7>44i~&y;aQ_-C+ zEQp_hntNuyk<~Fm9D~ruY-+b$ zvJxzwMEhgTBP=EJMkUvetSnqFN@JAd3!Wlc97+Jh6b< zK}Jw)Ed|2Dy;LJn0)~biGAdlIXx)ie^Y+7p(Nm_Cst(r3@yIk3xJ%J>;iU2{Z<6td zxdDE-@%p!+R_sYy!q3=z1Rqtdk(AY88f!1ZaU;^mD=Br7xCpb$4tU*D*8p~FaoqB& z7*Bu)yMjYJ(_1HrTekH=Vn)2o_|!U7<9tfIJHeTbj3KO=748W1`p=0aSj?v_oYY*W zlaqfSBK6G#%g&yKS11lgB{noWiz2 zg0pYZ@r>*1xP=`~rsmJH67X!OcgMpETAfzOi$ss+*85P~pnb&eIe0allY;gFipjU< z^At=xur_W73yX!^j`UiYG-qE-6~7=3S`mrW30|nH5Ot`ySVil8#^%-a2u7ZNSf3gG ztz_=nAKSBVD+~gU;@KiX@b`{}y`t9SU#R8z7i#sRw*NS1yldg$)dp)D`??QsBqYR( zQN~Ma52=ORi(G3|epN@n2AGd8uyRmj#pg=k^xe>xp&8Y;R;D&Ojfr%}GUZ188+Ve5+L* z{ma^DBXhERLQH8@IczYq5SH@=ytr1!CdX@Rh{KV~a2EYzLn>8)whi!;b*kj?-92uc_d3Kg z5T$_(#EIEl#}5~+!JEjnMr_T!wK#eSL3n7vOPldg$}{5{RRd~s?|!wNnh$B*)B{6X z1r2v!L<@=+%bhl^jH!1E-9?nUDH2bgz$rx`mBi6V2%$ka`_5~iSK7+{r7g+BHMzVN zo+q}26Q6>q{|ArX1_~QH;~0*j5AaqmWTIZ*fPcsBRO~BmA8`_IVEOBJphfe=0DtIP zgkGoSc0ESksq0f)tk&^Za_r0#j-3b(OOIoP39^A5t+tnCt(lpLjl3DA_@SSVwlAOD z0Y$Uq=x3QWVTJYQ`GJeA+q<{&5+w?1ifEaSYgKD`H4iUpLw0=a?`O`pV8`2LnT8&) zhv<>&h4zh@E2=k)#(rOa$e%xh0T{(VAF$#erh^6VLC`6-EgF=4l3zgni`)VOF~@x5 zupI6~h0!fk9dYMJ>4})vd^eOr3v-ukHW?VFTGFmI`55P62dBOHc?hc4en!w!rQ3rE zajVHjQo$S-AG}E#jP^`*uy$NRuBl3sx#|Mam(la(Tv^4?_hRFiIb;vpKIs`(|4)Ion!99I4n{HuKXEQ?)XDmInn|O;;KmJ>QKP4Xu4bZG zNdEcnt4@tBZbvIT%1H577XTb{{m*<7X2yFiq+=qh0!a@9)l$i-qyxc%lO^(O@_C6F z^DNi_F)S#6)P#tuOcknP9X)1(J=}xHs>#9)p;kXTjj|(4OB3}+f%BPV5vzxtX9b5I zDjyCt_DQb#%(wS;o+dER>1_2`k|;A7R__?$tWI&J>^iieZ(C_}0)ViO(N}6~5hVr1 z67w4@&>a*y9fvU7H{8?Y%=}_rv;sBrYx)Mf=}!lTrAdni2Ih;)qigJ)(UL_!;vg|~ zH`c+)$xRVA`Q+rtBWT5Ckct+I6T#S}SpoCCXDoAHMV86)c2zX&!!5!rrno0-P4X~o zT%~IRWBPfQQYWsdvw-6bSbX1F_4x% zSUql8$`g>bK{l~@7UDA2+FLs$f@h`X$=mJj0a|B4?a{O%`%k=npcn86o*iP+Mch@u zD@%R;#ZumXv2-o=%j-1$DdQCh(?(E$h?vTtO%l9Yfx-K^`kPpSKpZ0Vl{@u0k5iHK zBf0nzD{3Ry(z{r=ENy|WwUls`O6leKPWY;jU)k!8>Zza3bzt66k6)Dk7yqKmVsa3hm(??br)qJ#FAFgB-QCgNR3e+Qs= z*HkyMhKTV~kfIR$mvy6_)9OBhdFm(qy}4GMq8f6gebus zWnx^|PjUPr+7di6(Q^~^bQprSw9Atcwli{=^~a^Q1EZYDNJ(=wc~C%|)x%GdmyY?? zRKG_W!GsLfZ&h17%dCzTZoueoxhbeaBZwXve8kGyb!j|Mo~u3( zx#tO39ioWTUrbC@`8tFLDA-qv_uD6A4SG7sM?x6l#rEzsXSU6i;cOol%A~nyR^LK} zBnuKWu#IEko3$da<;Z~_t=csqG*cNwtySo|C4Ld9bjvg{fD4u7sHCQ_qbua4iNJLf$k*`Puf|yc*SX#qpwsPxa`mNcP7Y zb^{h}j6Sm1pT1Qhd3$|Sq`o#{vqmV?;0oyMQlaP0$WshvFCO8B{n0;c`MJeWlR!|9 zcm*CzXT~OLA4+hIL6Zy4_uW&M8}@t8ab!5~8;#!kuCP2!(ZEKn7JaI^i2IYISDH4k zH}h>3`h(=6NT7y4eNujyF(+K==C@hL1DgBf1a@&>TT@)pft63=)rkjlDyu6XaIbjA z8ibSz>~!@Fn~sO9j*NYAkxfsThVCiy%4${gf>aV-t{i6+$-27k2YPjUi3Lym1qMa> z!CFMNX&+=nXA+jaDN3}~a;AgU6U5NGS**fJhC9$8a?x$4D{EqCp1yapvYH00MX#9`<_`mA> zu;1@%*HY~vX6T}E5;L_Jv6}{2ZSg zRlUeu?%rMGau6uZw&T4NRM<@Ayn&@3S|RnUIcI~}U%@|k?O1(Zn_>Av#ZVV*CX4C@ zw@0Q!r1k;C358UX;zKB${Q~*dlIFxu4Jku|Kr_gHqyKmR!l>fsSB!?9Cf$=UZFGsi zQ`4E%QAag5l-PKCjG~t=rY?`Clsw;{N(_}J%GY9&ndQqrhauhZl9fYVXO5+#W7x>p|vZM&@yjqo74Wo;)SIal9O-Hw-A7v8lf=pfo=So?;X zxqrJecn)O7$K#o9d;TAYdipyQ?*gXOeHVWqIwk}^^0Bf?zkYF~FdqP4-BWwt>A=Xo z9}B9L%L-~$+R4t`Q`Om5tuD?3T`G*UPMk2#UWDZJ$0I>fB(q&ffC|_JGtKp176q9edfH zcZft^Rk`-x@&+XL&TiQWIftmicd<@kp5k)9zfhO0!joRQEzkdSOFi^MI}m+;B5$Pn zTc-8Sznf0YmGajM`Ir=b!_sbog^?e)C9Hxv^^UbjBm6bMuVarmkBo~e3MQF2iS-D> z?y&?mHWWM#hqvz!C$_xgteo-vJT`)!+(#373>lg)&Udm7!dzZ_`Kh5B6^6HuDutOB zg$R#MtMW@_2C8KyTq>Ovih7-);bSPSNVdnpycR!uRYx z%3|O4BHxphl%HZG1FO%jMOkZgFEXeL&(3lTex6FpRKwbAiBhNWHjGj$Q67Hq*4I_ zc-~~_#1LgMLk%CO8Q|Qkc&0+qAE>dn@{=Y*Q5(m-q248>&JbR#8n{t=mtaqguYz;! z@jI0-gK#9N@qCFloN2|X>YNQh;wVX~C}ZJ9FqS4FlRh&Qz-Pt~jYhSaKxw8Wx#z|NS+;_Jo6}fJLmC zE+>ph6XB=wbh6?OzRKu5BF~-g6y*5ZQc`cVP>^-OXl$EuQhhlMK7`Lhk8mLH7@iGE z?;(jP-m9~kLw{XU2a6Kn0_<%6!h-xO7O+EZ{$Sy>O9WC;WsnYm^Vn5Gp#Ne;MT*A+?2|rtUOUc49(D0qF9-G;OCZ#Czpq}yzTBHoXUlozf~H;? zE}|EtG}#Zsj#1S9kNQxrT+q>)?0;af9F2f|<-!4w-50<7$_2k=6qm0s1}NZK6IpC? z1(&61PKt&bHU)iohyo0LlrmxQKU@G72FLZSbXJ3ARzG^^lSiMRS0&5c&wyUJ@c3zl zaAX0|mu!a}Z`bNv?u=C5EcAs(?hhBf{o%sN-TZT+A_1P(blFP_+j*+?;)oyA2B12$ zuM;`L$oMHNMhIb~ywb19t{to)`XafPtB^az^&v@>FuFzqmkIZCRJI;Vjc3zvzxDlX z*0^O-FUg5M29ld7p3}37*pd(T?!HEMmv6Bw*+3opir*%IIVBaZ3i-VedTfPYsmQlL zKWWR8)6QPZfFrrb4~9RL#r*+oH9&OCWB7$TjEtNoW?+T`Rh?^|_DzKnHE%$?#DQbt zwVpAy*qLl?Z%s&bIvG-=ty5f*10o+n2eo!OHN4aFY!MUDJpoPoKT9sJbASKqst65D z_@&Ul?LzLdq9ZN0+cApNK0PcunRr_)O`g?`5R;KjqyYq9u8yC4+7|{Ms`LzjX9GPR zf)U&X!-3CVo^1Q9>Ti2~?^s`5HwbMg?SFot$&(l?)ypEjZIN85_;~#yJ#_1JN4GFC zgTBgFqFAT~9~5U3+<1lEZ!=$`7C6tfb7R%w{%9bQsb3PGw@C`^()b$`hzZM&{+^<- z_7n2ZZViwy^Z-Sa7*_Vi$(m^)rMfz-{c>m=fe*lOnvYW6TCQ2~kBja{8~^B!Lm0A5 zK^2iqr`}Q-nf7S=+jo{c4kN6wBHidGCd&P%@xIawq%0S+llge$cc(~?Po9Du=23@t z)kF0rbGWJf0Dqw{1YeL%)!OokzTdkBl( zAjq~t9D_yDt9SA0iOWtv0gL(rVpPa-j}97VFg;&a{RNvhdKoQhHQF-b?kL5est9UH z4ht|yFY>Jq7w(PXILG7~wmYHfs$s18vWRX2or8wnC7p1XZAS|EyHtn8+x{M^oQxvt zzT+L^NV+l_BYw1(wMmP@$lvI-L$z$kB{d&s3lH#mAb2fUHwk!}TP#aWksC5h z)7+ymlSa4@u$4OpjU67eetM~xkaVg~NJ9h00&NVHGi70W5-yV>x4xUknxCQVu!V7? z1k-ardBJ;`W!{Gx=}$r#pSyN)3yyFLE`}0~Rkc>f{^>b~gd^ruGM6vI= zQCFcVT<2XYMoXaX=_9I(?l6Cb_+xocimRc13BOvNugL$$H}?OuJ=ek?+Jm5|0v&CoO}%)TfOe91qfSQnEh#Ge(H(po<3x-)9OsFh7^VYs9J=kZ*O>O zb$@svwUY8!_iYcEjdP`tw4pmc!1r*)U{`XRRODRXg~Rj-{_-e0T1zVId&4_+{BZ-W z`zI*|(YJiz&nj}YgN6-Xt9{o1dl@O?L%+Jc!89Eg2(jJ5yMKDoo%V+iWdq6 zE^}N|XWmW^;Qiw}*{P%c$PMEmTH^~MJFAqjn`)My8*Xozceu&|xuOz`bfjvsqrqIa zxE*HZX$4VKU!L;5n=_vWhn0kf6lSxk8ki@RCFcRpGQ7=b>;y-R>=rysttRORn8bAG zLG17Y8xZY*YB0=}KYupF|I7EVxBm$qh5sjb1k!gr{sfQqX`zFJBykJ>V|$D_{?qk{ zzPcXmhx%;o)c%Vl0aEC@i_Pl0V$0QAvj1C8PSjlaGYRnYYI@$bLt#|CXM2=Rq<%%) zcl6g;HvWF4XiF^avqZLm0hd_I{@I-YHbC$A+>7gKZy{@KFRsdt=UK=v_RO}TX3dc1 zbJ5d-Fn@H>)`iy~9R>sE)sQg&!Z(OH1301=?#zBYVh6^U@|ksFP%wqm@`URu&!n1j zGE!S9dU$`XKXf?l`$`KZ>!I%x#Uga7pOZ*9u!Ws=Z>O{PB5;@->=F_zNris_0*sze z(GwD;ZjGuS3gHV>7mj=Zv?TNM57mp5+MYu)GCRD1yLZIGu_;@EEBc`q6t=zX^c2rn zC6t`ZRJ=rL7%{8iRNyUb?xHY>*-lw zq81Hmg=i)dd?w5UfYaXPMk41Hx;waR660gDw!O z(Uo|p87rO27c|_=Gkin2*#w+0#d87Dl!Gd#^n@seM%zQ_!dbpU9Vzmsd zzH*W~q{g`|~LeHx)&Tw|CR=9>rqM?FG+8%m9;+YhWI2iEg3U)|Tu~ z3I;|E&L+lIVKO=43l-b&QUt98-1YeS^{~B)4kjI!-OJ~AwIGmKeaMZ~s2?e`{gn)i zH9%{lOxCpi_Fkk>|G=yeL^o_V+KlQMbo>#WGWT|7gew^GmGMF47M8LnPTXI zyk%|93I@EPXAhw+_a!wKsIUejl6ku!q@fBrF+U9R?{$-}aVDY0=WUy;UPP6HgJ4!j z82gf>U~Q1-_@k%-uSspYmozyK=h3@vt9Yd6H;0|hu#h8r2!s6KZmf(kb{;co7XeIA zk2A!Td2uqe!X%p??}@QDf^<%pli$Yqy0vq!s`Epjrjw>FZp#&~6>oZ|w)T@_;EupV zjVEqc4R6HsAhj9)EvNQOY~XBmEs8sK7|Ijw_(pbI7F{qnjoN>PY2>$O_2-X&$5=YO zo0|XW$W&e#+Vf1=+b|_W)|>om+U;Z1{WWO??YZTNzxqN%JMC;uhQMb?SHLHkXrbDV zUv4$cdp_xRS3hR(w9QgmwXLgA zUv5KK;C1t!lfKoXyuq;&hHz#BfdsALZ}1sF;%*~R%! zZLH0Bd(hJEKvhhVCR(WF^Zp9K51`u(jnI!2PQEY-kLP}GXGIN@e~ZRNYT3XOF%PR< zHc8JC^NkE)N)jRCS7xc`;;<%zQjBj2$y6Nx**rzg2W3?GZA#N`HC^ZkPMQOc9K3RGDIN)Z!?-cO1z%t*jH2Z8uR^0 zpf)wOGZnWow*L6X7@5s(*aWc=hi+YTolxxhC@u)s6DdYvxlisKLk1RVOn!)tK0d)a zQx_gG&Z7DB=J$o`oxRPuDZgQz(#XP`4&veO`r=jnk<*HalsxQqo^m#~!_s76eq`kC z?jZ3CA21=O{tiRQ(O{(dlWEE!Jm>Z**`n}*75$mo<&XMK2||V#61=lTS*+_x=Pm#8pi^o z-XOZvY}&z36d6dPhc-;KruH0S>y~GFHhDFlJG)(y+uSE)fG4SOVf?Ccrxk0cxoIE( zefb_X{E$Jbm~*bs>=vr9x*e+a99d zh02<)0xMBhS3MeKBFBWr5%r)qW*VmkI4N#uwD1|I_kSby(FrCQ!Ghq#-%k)@DjeHK zY~EY{8q~#}s1i^M8zveKwBfp%KetXY(vFu@+8^`9I4Lg$qHXUArJ8VXD`Iig2!)Q2 zZBJZ{=o-$knl&(@(#60O=|R=V6-^+wnwLl7XCb%1B#$oEty~p?&KKR=Th~sdq)rP? zQhh@pkh@)SeyVI0`-~&LU z^dGxifADE*HkXyylQVA%${?Yr=D&OXx(K@=CIZDyfrRIx`KI1>Jg+=Q)k)M`I%zme zilV@H0`S!!K)EsK;M$C1opJ5k^52xBt5}|jLy0{^eOaizY~GJj?yI6UqDTBZj9Uni zhUll%yI)@?#h5=caw-K!<{L7U5(LY5TT2)21$R%4FK|sd^Zux|x-y4sSZ)bEFzYq5 zvV`o1W*U0IPsgXrn>^l%hY#=?*X=9imhvVapy>TBKE;7A%OuxP~PS& zTX>P}>X~Robr~b$@C-SbHvT=)T^niJi3RoBMc7 zFaL*p2uNno|L^r2a3sGf#2I*%pOpB&U-Wow`#&2F92i%Cg7}{-a1e;_e}DV?O@Rbf z7hod(CvO=9!v7CJ7YcYw00&$tzzWHT{aTcOe1rFQkANU6BsAgQV&H2Lg5+;;P!Nas zpTxQU?u?84j|hSrTqS@_{7=%yf6LHl{>pg%%Kll;{BPMP<6jx?U)ewN_5UpkV*e|9 z_gD5Gb9n!8pzz#(WRUD^e|7&63;%~slmBmb?60Q;2fQXo2stVYz7wP-{>LVRKq&vw zLS7ooCqzd4&!7!@y`cZT9m|2;ghU{n6u{pZsKKj343I90V0dAENGWBoKQle}qcA%0 ze~(4~w13nDrwdd5i=^N#VI0VhAHa*kZzTSKz`sVXe_H(30fEdMOjVp699>wA9UcFS YWh(M8uX*c#&K*9;@U^t1|EKo<0AGq4X8-^I delta 5521 zcmZWtbyQSq_Z}F!grQ+*=^8}3OF~*Yhm!7)9vbNwQtFaQUSN=xmXJ_-0O^nhk(BzO z_xqOXyT9|tInR3ce$P5wUj$lt+Q3YL}Q}QKhktE_X z@vJ4F#cbTWvN_ycddywzqVTs+Pzh8-SM)%Oye*dANi|7fnCmLwb%!OPP`{Ve&V(n? z^*2>U=nU;jCpctJ3RMp^AW^3IERs_UM`&tc;#)21P%?;OkRUjCoCTx53wS6nWgQsF z-+W;bWd3Q-HdTyVM<6JF)>r^X`(zA&`z{#koDMFNJDMv)JsQM1Ay66*EmznWn`IYs z9}yblicFa>mf-gn9q}^N<>thtc+WG=%6>~49lUW?F|!vu{B3Z|(i=Y;Cd2xEuXGlc z#K(JRX)@KOK(P3xUcnoar`_%7m=~^`xv)J*9~7i;DV>NQUKN%iN{l03y}VHeb4g%% zw{+aTCd-zKXE#oK zOdP2lU)}nq1wz=Rd&*p6l?ibxeBWi9A4oJ+g382RKNB4aqT)goY6Ttf3AiS zQbt`~N*E_S+g4Q~uv0US?z~cB=ck6ob!BoymYdqn$xiBBniI9UEntz*DuZ>&OyR6m z8{h9dGuuE!O{mVv7!s^suh1k{iFm%^(6jtAGUNRjD*ekUOG}B63Y9$cS3k-&t@T0| zIITH3VFZ~#m~|KQa0yM(_U{VA{)HOuK2qsD>IvIBCOO6J7g&1V_?q#s_i{VyHCZ4ZKQG%XYEfe zgIW#98?rS#83#|5@;2H@?!qONS@LGO_wW&;xAtfu^pAX~z_>MCx2A!Q{4Qmd7&w!! zVS&aCuLymtKL}Dj`mz_jsn8Ua_mfJcws^HKzQK6lhXAG(zgq24RLnJT?y7q7`x5d^ z!BvodiRIwo+&IwiKs}l0luPQ%C8SYGZH%?|aR05BL1Uxsv&=;qDv$CiGXr?ja7qOO z`}WzlO%LHfix#$SWx5<_{oHkUy&rZw5zJ$wj2^){*C1VhOqI+^-B!ANJ%Nl16q*Ll zsy%h`Rl+46p1DCL$dUJ0D14XJl(G~))q#qRsPIp9XSr$19c3KoMS&SV0-a>UL|lI;^mD*6bxpGCwsf`6GYZqk9JW#obcjjfUagbZ(scPb))KEnsq;1$1BQJy z2nmW&&|m8y?!}Ajrhkn^-Bhz`HJV)5oA2sC+o;OjQGObl;D6M*qa~ zDUctke{7;EJhZeT_ftMD*-H~$?yL7ofU01_hcC4ujOtny78}$?6ru)*^{IMO62+K2 z+Ci0zI9?wO4Z8d?`O`0k)-Nb$LM6eI2ZzB3q?6P1X}JZOMqT{%`3{W#24zYARCfLJ zO15|VyTyrH;X%+7zaZskvh$=RmwJW)8M&W4(LylbuRO*XmHzfg;DLB=&=DfI>?p9b zA%{K)Uer-!hurZ8_f*4H$Pm~F$8)YR&Zf6Wsp&g5Dq1~J zD(y03W8VcNPn6>ryA|$edX_>O(br&KGU|ceAs`!&f}{PtTvDIwAV?59DeF#hOr-cDL>6dk7#UtkXpbgR1}^rn zSq*Q=o1)yMraiD5BD|hw@~u?8 zh#`HtTNh@OR0Dn?8M`@>!4(9#n5+?4BIQ*|26k_&T<2V^C$ox)UH>LSe0Fpykp(mW z;E(_Spn$uJk;8t`UvAn$Vh)5b>WK4Ys-+s_G6L0!Hi+-M$@H_jRKi!K@s%Kow6z*2iu^Ytp0EV|zBT9YLn2&-%urW<;v3 z@v-N^SuQ4%=va))^;*#&1R#gJLty>u<$ zInx5e=XdLDjPtmq7+#C29#CMiI7~=Y!=GO28|jyjx^pctOa7H5#~4+8-??jA(L1|T zE|vMcP9HY_T#yczlbKETOIgtPLe(1;aY&e1zWB|(qaggHZ&$7RVOL|`5DvrT5musk zEEen$*5cfC#<#M*K^k%T_VzSuO*AV1J8K6boCYY~$^ruGbpa1jQh-7EU) zjnO^S&-?q|x2lW<^&V-$DDzU6_;CvR=Q8Ne;TaxJ`T8$WbF@*(L*`~C7sM9OMfr0p zQgCIjd@#=oT-(kNhHtj&Mr>9pr{9*sM0-f}&RH@k10CAjzHbUzPvi#<*k_asw=?Cw znI#D=*zRV)3;Fv=^BvY<;5F0nf%Pck2>4TL*5V5?t1a!B-YRuNIs};wa76r5RMw)l zAme=`w`IHqTs^R_s?J6*qFt?ZEOjOYm(%a_$#hYtHZJy1zEcQKQS=T*Z7pLjtUXLb zfK0!sWRf0Lc$(QK>SF`e5oVc?dII~Gfo9c0P1_JkPO--$7A;8-=jk{3dwI}EVH-OOg+jt9S z%}l67rC)0OlB>VA3x1PVBHPMsGz_&B%Sb~I&XI>zX`r=O0)$Zvq z+Y<$X7Hw@e^cjyXQlp5rupL@`$W{%s-)EkX9}?;eRjq8c?7#m+npM9Zt3REt_CvjG z;_{KcSBgXpg_KheCiK<7;E3?!XUZ~o+w&-Vc0@cFWdVI%S#hD+!~Rkw$)-7>_N4qH zm*&|hFMLMqbOfv>D<)rV<0mHVOVK=T9dze6I8Vv069_*TK6D4a7^&K`z)`8SYDwY? z2&91ae#oMPV%{`fKHEcbpt&{qyKtS zLRpE!0dw~)8CpS3x=xMBJ8!w8z(j{Z|G%jhpurPa#<+ObPX$TPDrH3Z*LcgKgKD>qTJldP`*9^ zOmm1i!;T##E7QeW$z@rb6Uxj>f3n~PpdE&O)^n6}>?{uGkpUUSm9D8U0l%VV=E;L( z0uq>4ovO28x|K1|z}Yw^PB$;`DH_njpm5pPt$>V&Z%iZgCHfD_<6%v1T;yLCL2Zs* z?Gbw07P(924MK1Bd)WN$BK6$$=AJrbtp8OgfRC^_3qwH0>YYI5eccMV^7b2`dfL*+$HL!r#HrYuF{6q8D*0+>&kUUQ9VH0UAA)4*;`a2 zxgxdh6ETh~?{$`c6LrKThoPMh#jieR>w7z1(`2dUy}DJV5H#O^1izHxjwsIo!Z@eG zbH!otsJoZ+LN3sD+UYvrC4_Midy`;8#s|7_InR>OyG@A|GGp9dSQjiO)K%5W6uQX8 zf9~!+C20@}(rI8Zc5!(WEh1SXH4*EKo@V{!XWwDEJK?Vdq$KW(g}MfQI-{(RV+G?; zkDGM|_mt|I*ufmMxES(+$-d##kDs2e!8R@5bJWx0WJoD$eC4DSzF?HA>+zlU@WnVI z++VpF)yh~OFMG8-O6?Y~A3#>x-S!x-eN7zegD^9(Yid5LSxUq>M*_LNa!P!lhS?<{ zMli*>MuoRzHWdq-t%rGKP-MS08_1~ut7loiN9yit_C4w^k_H0)D_-GdVi+*+#3x;h zhZYL_U?llZ4%%6G*jT^t^00TY{hf;ODSR5e5W>h;kMF`av7=^`lR2c-Md|sxr5oNc zdB7bli3-AxKhXYJH4LjOq1OwE5{ptw3A51I(^wk?R$_0ltRVC_q^uL5S(!v0Mvm zwp=P&*F-I83SN}s!AZwY!ULH&)fy*EQk?U~V>zp9pi%GwZ4%J}#;D=s`d7kouSpq9 zr#kNC*U54*K9~Ezoa^28Lda!Im2AlTx|hOCG3GsM&Er^vF+F!>NP3EphD3BsiN(#F z^*1|`-fv1D-KQMx?+V{7R$eadlK)nXFx5C5SYQ7=`KO0Cy?KZk;Xm=RvT(AJv$L>w z`9)h!$)h+u5WF;Hb~S<%*^ITFCep6A=PZl@zi z6CE#Hb8*3#TK(owwI(U<{Cp9bB2*)Hsxo1d;arY`qPY=ffH6&_^cjjNAH^cgWcI-g z%?7Q!27FLBvS8+7=@3@Asqa98vRZI1q^>f(UaNBpi}ZKOt$>jguIt9J!chcC(O0y| z7&Q=~1}rErEyr*ON#ru-^`q2RYEzASVMYdubp1HtB7)~+sS6y_Y|5g0o#qWQBBJM6 z0qPyOp2`iP>5)IsRlcRiryLP&glwb_Zc09L-RU=FRHSA>=j6cVbC4<4^#~yT{^mrb zJFdb(lLhm@AayEjmhV%1IeY&bTg@j2hS3dcHQLPlu=984%`b1d&O?B*WX)*3X#9Au zq?>4C?4)rd8TX1g{6khKaM)z15`sPtNSOgEreJ2<=`n~AHRAWN@dmBINWSyoV=<$rw`5x=SyY&WDg9%dM%>n-6Piox!2Y^>-cznQvav3;+wOYg`H4@$i@v;>C-<-(37_Jzj{%*QdG%)?W1XjRzR*$v{dMi|0eOnfH0r zbUg;K)-jx(mgr~i*DwOD*u)tc4iAR7pRS@~q{Da8eY6ND4H^tT1LU$S$Rg(ySV9kL zI|fn9$A-O)(gOGR9f{8fo%q-(b^BSlLc&UVL@djPpf|d%3}4XK7DT>xK~55dcbM$H z`4VrR6t%X#Gc(t5m5i6jwWeC3Iq82-yU#~jwjJHb`+X?$5Cv~`tvQs=jD)^;22PzBo?^O{fDSTdv5bw`>3~Awn zmdxOP_g;S-kj!u`OFHns3&S4=eRg=fr8H_12Yk#@12u&cPG=>CYRwHdu@V9Qn;!q{ zq7s1DSuuit)5^o?w|S^HM1QOg2qXwUvSI@NNsoUB_K#1NFr3GliU0%v0a_mPs+-s^ G)Bgd8oA~